Add parsing class parcelling tests
Uses reflection to read all of the getters for each of the data classes and finds their setters to input test data, serialize it, deserialize it, and compare the before and after values. Also records all of the methods available in the class, to ensure that any new fields/methods are caught by the test. Bug: 178852754 Test: atest com.android.server.pm.test.parsing.parcelling Change-Id: I642fd43a3ff2e5675129f0f4ad3646c97e3f0e22
This commit is contained in:
@@ -55,6 +55,8 @@ import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.overlay.OverlayPaths;
|
||||
import android.content.pm.parsing.ParsingPackageUtils;
|
||||
import android.content.pm.split.SplitAssetLoader;
|
||||
import android.content.pm.parsing.result.ParseResult;
|
||||
import android.content.pm.parsing.result.ParseTypeImpl;
|
||||
import android.content.res.ApkAssets;
|
||||
@@ -7425,7 +7427,7 @@ public class PackageParser {
|
||||
mCompileSdkVersionCodename = dest.readString();
|
||||
mUpgradeKeySets = (ArraySet<String>) dest.readArraySet(boot);
|
||||
|
||||
mKeySetMapping = readKeySetMapping(dest);
|
||||
mKeySetMapping = ParsingPackageUtils.readKeySetMapping(dest);
|
||||
|
||||
cpuAbiOverride = dest.readString();
|
||||
use32bitAbi = (dest.readInt() == 1);
|
||||
@@ -7551,73 +7553,13 @@ public class PackageParser {
|
||||
dest.writeInt(mCompileSdkVersion);
|
||||
dest.writeString(mCompileSdkVersionCodename);
|
||||
dest.writeArraySet(mUpgradeKeySets);
|
||||
writeKeySetMapping(dest, mKeySetMapping);
|
||||
ParsingPackageUtils.writeKeySetMapping(dest, mKeySetMapping);
|
||||
dest.writeString(cpuAbiOverride);
|
||||
dest.writeInt(use32bitAbi ? 1 : 0);
|
||||
dest.writeByteArray(restrictUpdateHash);
|
||||
dest.writeInt(visibleToInstantApps ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the keyset mapping to the provided package. {@code null} mappings are permitted.
|
||||
*/
|
||||
private static void writeKeySetMapping(
|
||||
Parcel dest, ArrayMap<String, ArraySet<PublicKey>> keySetMapping) {
|
||||
if (keySetMapping == null) {
|
||||
dest.writeInt(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
final int N = keySetMapping.size();
|
||||
dest.writeInt(N);
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
dest.writeString(keySetMapping.keyAt(i));
|
||||
ArraySet<PublicKey> keys = keySetMapping.valueAt(i);
|
||||
if (keys == null) {
|
||||
dest.writeInt(-1);
|
||||
continue;
|
||||
}
|
||||
|
||||
final int M = keys.size();
|
||||
dest.writeInt(M);
|
||||
for (int j = 0; j < M; j++) {
|
||||
dest.writeSerializable(keys.valueAt(j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a keyset mapping from the given parcel at the given data position. May return
|
||||
* {@code null} if the serialized mapping was {@code null}.
|
||||
*/
|
||||
private static ArrayMap<String, ArraySet<PublicKey>> readKeySetMapping(Parcel in) {
|
||||
final int N = in.readInt();
|
||||
if (N == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayMap<String, ArraySet<PublicKey>> keySetMapping = new ArrayMap<>();
|
||||
for (int i = 0; i < N; ++i) {
|
||||
String key = in.readString();
|
||||
final int M = in.readInt();
|
||||
if (M == -1) {
|
||||
keySetMapping.put(key, null);
|
||||
continue;
|
||||
}
|
||||
|
||||
ArraySet<PublicKey> keys = new ArraySet<>(M);
|
||||
for (int j = 0; j < M; ++j) {
|
||||
PublicKey pk = (PublicKey) in.readSerializable();
|
||||
keys.add(pk);
|
||||
}
|
||||
|
||||
keySetMapping.put(key, keys);
|
||||
}
|
||||
|
||||
return keySetMapping;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Package>() {
|
||||
public Package createFromParcel(Parcel in) {
|
||||
return new Package(in);
|
||||
|
||||
@@ -535,7 +535,7 @@ public class PackageInfoWithoutStateUtils {
|
||||
ai.setMaxAspectRatio(maxAspectRatio != null ? maxAspectRatio : 0f);
|
||||
Float minAspectRatio = a.getMinAspectRatio();
|
||||
ai.setMinAspectRatio(minAspectRatio != null ? minAspectRatio : 0f);
|
||||
ai.supportsSizeChanges = a.getSupportsSizeChanges();
|
||||
ai.supportsSizeChanges = a.isSupportsSizeChanges();
|
||||
ai.requestedVrComponent = a.getRequestedVrComponent();
|
||||
ai.rotationAnimation = a.getRotationAnimation();
|
||||
ai.colorMode = a.getColorMode();
|
||||
|
||||
@@ -360,7 +360,7 @@ public interface ParsingPackage extends ParsingPackageRead {
|
||||
|
||||
ParsingPackage setCompileSdkVersion(int compileSdkVersion);
|
||||
|
||||
ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename);
|
||||
ParsingPackage setCompileSdkVersionCodeName(String compileSdkVersionCodeName);
|
||||
|
||||
ParsingPackage setAttributionsAreUserVisible(boolean attributionsAreUserVisible);
|
||||
|
||||
|
||||
@@ -553,7 +553,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
|
||||
|
||||
setCompileSdkVersion(manifestArray.getInteger(
|
||||
R.styleable.AndroidManifest_compileSdkVersion, 0));
|
||||
setCompileSdkVersionCodename(manifestArray.getNonConfigurationString(
|
||||
setCompileSdkVersionCodeName(manifestArray.getNonConfigurationString(
|
||||
R.styleable.AndroidManifest_compileSdkVersionCodename, 0));
|
||||
|
||||
setIsolatedSplitLoading(manifestArray.getBoolean(
|
||||
@@ -2686,8 +2686,8 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParsingPackage setCompileSdkVersionCodename(String compileSdkVersionCodename) {
|
||||
this.compileSdkVersionCodeName = compileSdkVersionCodename;
|
||||
public ParsingPackage setCompileSdkVersionCodeName(String compileSdkVersionCodeName) {
|
||||
this.compileSdkVersionCodeName = compileSdkVersionCodeName;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
import static android.content.pm.parsing.ParsingPackageImpl.sForInternedString;
|
||||
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.content.ComponentName;
|
||||
@@ -423,6 +424,7 @@ public class ParsedActivity extends ParsedMainComponent {
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Parcelable.Creator<ParsedActivity> CREATOR = new Creator<ParsedActivity>() {
|
||||
@Override
|
||||
public ParsedActivity createFromParcel(Parcel source) {
|
||||
@@ -513,10 +515,6 @@ public class ParsedActivity extends ParsedMainComponent {
|
||||
return minAspectRatio;
|
||||
}
|
||||
|
||||
public boolean getSupportsSizeChanges() {
|
||||
return supportsSizeChanges;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getRequestedVrComponent() {
|
||||
return requestedVrComponent;
|
||||
|
||||
@@ -43,8 +43,8 @@ import java.util.Map;
|
||||
/** @hide */
|
||||
public abstract class ParsedComponent implements Parcelable {
|
||||
|
||||
private static ParsedIntentInfo.ListParceler sForIntentInfos = Parcelling.Cache.getOrCreate(
|
||||
ParsedIntentInfo.ListParceler.class);
|
||||
private static final ParsedIntentInfo.ListParceler sForIntentInfos =
|
||||
Parcelling.Cache.getOrCreate(ParsedIntentInfo.ListParceler.class);
|
||||
|
||||
@NonNull
|
||||
@DataClass.ParcelWith(ForInternedString.class)
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.content.pm.parsing.component;
|
||||
|
||||
import static android.content.pm.parsing.ParsingPackageImpl.sForInternedString;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
import android.os.Parcel;
|
||||
@@ -94,6 +95,7 @@ public class ParsedInstrumentation extends ParsedComponent {
|
||||
this.functionalTest = in.readByte() != 0;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Parcelable.Creator<ParsedInstrumentation> CREATOR =
|
||||
new Parcelable.Creator<ParsedInstrumentation>() {
|
||||
@Override
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.content.pm.parsing.component;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Parcel;
|
||||
@@ -58,6 +59,7 @@ public final class ParsedIntentInfo extends IntentFilter {
|
||||
item.writeIntentInfoToParcel(dest, parcelFlags);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ParsedIntentInfo unparcel(Parcel source) {
|
||||
return new ParsedIntentInfo(source);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.content.pm.parsing.component;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.pm.PermissionInfo;
|
||||
import android.os.Parcel;
|
||||
@@ -167,6 +168,7 @@ public class ParsedPermission extends ParsedComponent {
|
||||
this.knownCerts = sForStringSet.unparcel(in);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Parcelable.Creator<ParsedPermission> CREATOR =
|
||||
new Parcelable.Creator<ParsedPermission>() {
|
||||
@Override
|
||||
|
||||
@@ -19,7 +19,6 @@ package android.content.pm.parsing.component;
|
||||
import static java.util.Collections.emptySet;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
@@ -169,6 +169,7 @@ public class ParsedProvider extends ParsedMainComponent {
|
||||
this.pathPermissions = in.createTypedArray(PathPermission.CREATOR);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Parcelable.Creator<ParsedProvider> CREATOR = new Creator<ParsedProvider>() {
|
||||
@Override
|
||||
public ParsedProvider createFromParcel(Parcel source) {
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.content.pm.parsing.component;
|
||||
|
||||
import static android.content.pm.parsing.ParsingPackageImpl.sForInternedString;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
import android.os.Parcel;
|
||||
@@ -83,6 +84,7 @@ public class ParsedService extends ParsedMainComponent {
|
||||
this.permission = sForInternedString.unparcel(in);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Parcelable.Creator<ParsedService> CREATOR = new Creator<ParsedService>() {
|
||||
@Override
|
||||
public ParsedService createFromParcel(Parcel source) {
|
||||
|
||||
@@ -55,6 +55,7 @@ import java.util.UUID;
|
||||
*/
|
||||
public final class PackageImpl extends ParsingPackageImpl implements ParsedPackage, AndroidPackage {
|
||||
|
||||
@NonNull
|
||||
public static PackageImpl forParsing(@NonNull String packageName, @NonNull String baseCodePath,
|
||||
@NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp) {
|
||||
return new PackageImpl(packageName, baseCodePath, codePath, manifestArray, isCoreApp);
|
||||
@@ -70,6 +71,7 @@ public final class PackageImpl extends ParsingPackageImpl implements ParsedPacka
|
||||
* this case only cares about
|
||||
* volumeUuid, just fake it rather than having separate method paths.
|
||||
*/
|
||||
@NonNull
|
||||
public static AndroidPackage buildFakeForDeletion(String packageName, String volumeUuid) {
|
||||
return ((ParsedPackage) PackageImpl.forTesting(packageName)
|
||||
.setVolumeUuid(volumeUuid)
|
||||
@@ -77,11 +79,13 @@ public final class PackageImpl extends ParsingPackageImpl implements ParsedPacka
|
||||
.hideAsFinal();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@VisibleForTesting
|
||||
public static ParsingPackage forTesting(String packageName) {
|
||||
return forTesting(packageName, "");
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@VisibleForTesting
|
||||
public static ParsingPackage forTesting(String packageName, String baseCodePath) {
|
||||
return new PackageImpl(packageName, baseCodePath, baseCodePath, null, false);
|
||||
@@ -568,6 +572,7 @@ public final class PackageImpl extends ParsingPackageImpl implements ParsedPacka
|
||||
assignDerivedFields();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Creator<PackageImpl> CREATOR = new Creator<PackageImpl>() {
|
||||
@Override
|
||||
public PackageImpl createFromParcel(Parcel source) {
|
||||
|
||||
@@ -32,6 +32,7 @@ android_test {
|
||||
"androidx.test.runner",
|
||||
"junit",
|
||||
"kotlin-test",
|
||||
"kotlin-reflect",
|
||||
"services.core",
|
||||
"servicestests-utils",
|
||||
"truth-prebuilt",
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"presubmit": [
|
||||
{
|
||||
"name": "PackageManagerServiceUnitTests"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,572 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.parsing.parcelling
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.ConfigurationInfo
|
||||
import android.content.pm.FeatureGroupInfo
|
||||
import android.content.pm.FeatureInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.SigningDetails
|
||||
import android.content.pm.parsing.ParsingPackage
|
||||
import android.content.pm.parsing.component.ParsedActivity
|
||||
import android.content.pm.parsing.component.ParsedAttribution
|
||||
import android.content.pm.parsing.component.ParsedComponent
|
||||
import android.content.pm.parsing.component.ParsedInstrumentation
|
||||
import android.content.pm.parsing.component.ParsedIntentInfo
|
||||
import android.content.pm.parsing.component.ParsedPermission
|
||||
import android.content.pm.parsing.component.ParsedPermissionGroup
|
||||
import android.content.pm.parsing.component.ParsedProcess
|
||||
import android.content.pm.parsing.component.ParsedProvider
|
||||
import android.content.pm.parsing.component.ParsedService
|
||||
import android.content.pm.parsing.component.ParsedUsesPermission
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.util.ArraySet
|
||||
import android.util.SparseArray
|
||||
import android.util.SparseIntArray
|
||||
import com.android.internal.R
|
||||
import com.android.server.pm.parsing.pkg.AndroidPackage
|
||||
import com.android.server.pm.parsing.pkg.PackageImpl
|
||||
import com.android.server.testutils.mockThrowOnUnmocked
|
||||
import com.android.server.testutils.whenever
|
||||
import java.security.KeyPairGenerator
|
||||
import java.security.PublicKey
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
|
||||
@ExperimentalContracts
|
||||
class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, PackageImpl::class) {
|
||||
|
||||
override val defaultImpl = PackageImpl.forTesting("com.example.test")
|
||||
override val creator = PackageImpl.CREATOR
|
||||
|
||||
override val excludedMethods = listOf(
|
||||
// Internal methods
|
||||
"toAppInfoToString",
|
||||
"toAppInfoWithoutState",
|
||||
"toAppInfoWithoutStateWithoutFlags",
|
||||
"assignDerivedFields",
|
||||
"buildFakeForDeletion",
|
||||
"capPermissionPriorities",
|
||||
"forParsing",
|
||||
"forTesting",
|
||||
"getBaseAppDataCredentialProtectedDirForSystemUser",
|
||||
"getBaseAppDataDeviceProtectedDirForSystemUser",
|
||||
"getBoolean",
|
||||
"setBoolean",
|
||||
"hideAsFinal",
|
||||
"hideAsParsed",
|
||||
"markNotActivitiesAsNotExportedIfSingleUser",
|
||||
"sortActivities",
|
||||
"sortReceivers",
|
||||
"sortServices",
|
||||
"setAllComponentsDirectBootAware",
|
||||
// Tested through setting minor/major manually
|
||||
"setLongVersionCode",
|
||||
"getLongVersionCode",
|
||||
// Tested through constructor
|
||||
"getManifestPackageName",
|
||||
"setManifestPackageName",
|
||||
// Utility methods
|
||||
"getStorageUuid",
|
||||
// Removal not tested, irrelevant for parcelling concerns
|
||||
"removeUsesOptionalLibrary",
|
||||
"clearAdoptPermissions",
|
||||
"clearOriginalPackages",
|
||||
"clearProtectedBroadcasts",
|
||||
"removePermission",
|
||||
"removeUsesLibrary",
|
||||
"removeUsesOptionalNativeLibrary",
|
||||
// Tested manually
|
||||
"getMimeGroups",
|
||||
"getRequestedPermissions",
|
||||
// Tested through asSplit
|
||||
"asSplit",
|
||||
"getSplitNames",
|
||||
"getSplitCodePaths",
|
||||
"getSplitRevisionCodes",
|
||||
"getSplitFlags",
|
||||
"getSplitClassLoaderNames",
|
||||
"getSplitDependencies",
|
||||
"setSplitCodePaths",
|
||||
"setSplitClassLoaderName",
|
||||
"setSplitHasCode",
|
||||
)
|
||||
|
||||
override val baseParams = listOf(
|
||||
AndroidPackage::getAppComponentFactory,
|
||||
AndroidPackage::getAutoRevokePermissions,
|
||||
AndroidPackage::getBackupAgentName,
|
||||
AndroidPackage::getBanner,
|
||||
AndroidPackage::getBaseApkPath,
|
||||
AndroidPackage::getBaseRevisionCode,
|
||||
AndroidPackage::getCategory,
|
||||
AndroidPackage::getClassLoaderName,
|
||||
AndroidPackage::getClassName,
|
||||
AndroidPackage::getCompatibleWidthLimitDp,
|
||||
AndroidPackage::getCompileSdkVersion,
|
||||
AndroidPackage::getCompileSdkVersionCodeName,
|
||||
AndroidPackage::getDataExtractionRules,
|
||||
AndroidPackage::getDescriptionRes,
|
||||
AndroidPackage::getFullBackupContent,
|
||||
AndroidPackage::getGwpAsanMode,
|
||||
AndroidPackage::getIconRes,
|
||||
AndroidPackage::getInstallLocation,
|
||||
AndroidPackage::getLabelRes,
|
||||
AndroidPackage::getLargestWidthLimitDp,
|
||||
AndroidPackage::getLogo,
|
||||
AndroidPackage::getManageSpaceActivityName,
|
||||
AndroidPackage::getMemtagMode,
|
||||
AndroidPackage::getMinSdkVersion,
|
||||
AndroidPackage::getNativeHeapZeroInitialized,
|
||||
AndroidPackage::getNativeLibraryDir,
|
||||
AndroidPackage::getNativeLibraryRootDir,
|
||||
AndroidPackage::getNetworkSecurityConfigRes,
|
||||
AndroidPackage::getNonLocalizedLabel,
|
||||
AndroidPackage::getOverlayCategory,
|
||||
AndroidPackage::getOverlayPriority,
|
||||
AndroidPackage::getOverlayTarget,
|
||||
AndroidPackage::getOverlayTargetName,
|
||||
AndroidPackage::getPackageName,
|
||||
AndroidPackage::getPath,
|
||||
AndroidPackage::getPermission,
|
||||
AndroidPackage::getPrimaryCpuAbi,
|
||||
AndroidPackage::getProcessName,
|
||||
AndroidPackage::getRealPackage,
|
||||
AndroidPackage::getRequiredAccountType,
|
||||
AndroidPackage::getRequiresSmallestWidthDp,
|
||||
AndroidPackage::getResizeableActivity,
|
||||
AndroidPackage::getRestrictedAccountType,
|
||||
AndroidPackage::getRoundIconRes,
|
||||
AndroidPackage::getSeInfo,
|
||||
AndroidPackage::getSeInfoUser,
|
||||
AndroidPackage::getSecondaryCpuAbi,
|
||||
AndroidPackage::getSecondaryNativeLibraryDir,
|
||||
AndroidPackage::getSharedUserId,
|
||||
AndroidPackage::getSharedUserLabel,
|
||||
AndroidPackage::getStaticSharedLibName,
|
||||
AndroidPackage::getStaticSharedLibVersion,
|
||||
AndroidPackage::getTargetSandboxVersion,
|
||||
AndroidPackage::getTargetSdkVersion,
|
||||
AndroidPackage::getTaskAffinity,
|
||||
AndroidPackage::getTheme,
|
||||
AndroidPackage::getUiOptions,
|
||||
AndroidPackage::getUid,
|
||||
AndroidPackage::getVersionName,
|
||||
AndroidPackage::getZygotePreloadName,
|
||||
AndroidPackage::isAllowAudioPlaybackCapture,
|
||||
AndroidPackage::isAllowBackup,
|
||||
AndroidPackage::isAllowClearUserData,
|
||||
AndroidPackage::isAllowClearUserDataOnFailedRestore,
|
||||
AndroidPackage::isAllowNativeHeapPointerTagging,
|
||||
AndroidPackage::isAllowTaskReparenting,
|
||||
AndroidPackage::isBackupInForeground,
|
||||
AndroidPackage::isBaseHardwareAccelerated,
|
||||
AndroidPackage::isCantSaveState,
|
||||
AndroidPackage::isCoreApp,
|
||||
AndroidPackage::isCrossProfile,
|
||||
AndroidPackage::isDebuggable,
|
||||
AndroidPackage::isDefaultToDeviceProtectedStorage,
|
||||
AndroidPackage::isDirectBootAware,
|
||||
AndroidPackage::isEnabled,
|
||||
AndroidPackage::isExternalStorage,
|
||||
AndroidPackage::isExtractNativeLibs,
|
||||
AndroidPackage::isFactoryTest,
|
||||
AndroidPackage::isForceQueryable,
|
||||
AndroidPackage::isFullBackupOnly,
|
||||
AndroidPackage::isGame,
|
||||
AndroidPackage::isHasCode,
|
||||
AndroidPackage::isHasDomainUrls,
|
||||
AndroidPackage::isHasFragileUserData,
|
||||
AndroidPackage::isIsolatedSplitLoading,
|
||||
AndroidPackage::isKillAfterRestore,
|
||||
AndroidPackage::isLargeHeap,
|
||||
AndroidPackage::isMultiArch,
|
||||
AndroidPackage::isNativeLibraryRootRequiresIsa,
|
||||
AndroidPackage::isOdm,
|
||||
AndroidPackage::isOem,
|
||||
AndroidPackage::isOverlay,
|
||||
AndroidPackage::isOverlayIsStatic,
|
||||
AndroidPackage::isPartiallyDirectBootAware,
|
||||
AndroidPackage::isPersistent,
|
||||
AndroidPackage::isPrivileged,
|
||||
AndroidPackage::isProduct,
|
||||
AndroidPackage::isProfileableByShell,
|
||||
AndroidPackage::isRequestLegacyExternalStorage,
|
||||
AndroidPackage::isRequiredForAllUsers,
|
||||
AndroidPackage::isResizeableActivityViaSdkVersion,
|
||||
AndroidPackage::isRestoreAnyVersion,
|
||||
AndroidPackage::isSignedWithPlatformKey,
|
||||
AndroidPackage::isStaticSharedLibrary,
|
||||
AndroidPackage::isStub,
|
||||
AndroidPackage::isSupportsRtl,
|
||||
AndroidPackage::isSystem,
|
||||
AndroidPackage::isSystemExt,
|
||||
AndroidPackage::isTestOnly,
|
||||
AndroidPackage::isUse32BitAbi,
|
||||
AndroidPackage::isUseEmbeddedDex,
|
||||
AndroidPackage::isUsesCleartextTraffic,
|
||||
AndroidPackage::isUsesNonSdkApi,
|
||||
AndroidPackage::isVendor,
|
||||
AndroidPackage::isVisibleToInstantApps,
|
||||
AndroidPackage::isVmSafeMode,
|
||||
AndroidPackage::getMaxAspectRatio,
|
||||
AndroidPackage::getMinAspectRatio,
|
||||
AndroidPackage::hasPreserveLegacyExternalStorage,
|
||||
AndroidPackage::hasRequestForegroundServiceExemption,
|
||||
AndroidPackage::hasRequestRawExternalStorageAccess,
|
||||
)
|
||||
|
||||
override fun extraParams() = listOf(
|
||||
getter(AndroidPackage::getVolumeUuid, "57554103-df3e-4475-ae7a-8feba49353ac"),
|
||||
getter(AndroidPackage::isProfileable, true),
|
||||
getter(AndroidPackage::getVersionCode, 3),
|
||||
getter(AndroidPackage::getVersionCodeMajor, 9),
|
||||
getter(AndroidPackage::getUpgradeKeySets, setOf("testUpgradeKeySet")),
|
||||
getter(AndroidPackage::isAnyDensity, false, 0),
|
||||
getter(AndroidPackage::isResizeable, false, 0),
|
||||
getter(AndroidPackage::isSupportsSmallScreens, false, 0),
|
||||
getter(AndroidPackage::isSupportsNormalScreens, false, 0),
|
||||
getter(AndroidPackage::isSupportsLargeScreens, false, 0),
|
||||
getter(AndroidPackage::isSupportsExtraLargeScreens, false, 0),
|
||||
adder(AndroidPackage::getAdoptPermissions, "test.adopt.PERMISSION"),
|
||||
adder(AndroidPackage::getOriginalPackages, "com.test.original"),
|
||||
adder(AndroidPackage::getImplicitPermissions, "test.implicit.PERMISSION"),
|
||||
adder(AndroidPackage::getLibraryNames, "testLibraryName"),
|
||||
adder(AndroidPackage::getProtectedBroadcasts, "test.protected.BROADCAST"),
|
||||
adder(AndroidPackage::getQueriesPackages, "com.test.package.queries"),
|
||||
adder(AndroidPackage::getQueriesProviders, "com.test.package.queries.provider"),
|
||||
adder(AndroidPackage::getUsesLibraries, "testUsesLibrary"),
|
||||
adder(AndroidPackage::getUsesNativeLibraries, "testUsesNativeLibrary"),
|
||||
adder(AndroidPackage::getUsesOptionalLibraries, "testUsesOptionalLibrary"),
|
||||
adder(AndroidPackage::getUsesOptionalNativeLibraries, "testUsesOptionalNativeLibrary"),
|
||||
adder(AndroidPackage::getUsesStaticLibraries, "testUsesStaticLibrary"),
|
||||
getSetByValue(
|
||||
AndroidPackage::getUsesStaticLibrariesVersions,
|
||||
PackageImpl::addUsesStaticLibraryVersion,
|
||||
(testCounter++).toLong(),
|
||||
transformGet = { it?.singleOrNull() }
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::areAttributionsUserVisible,
|
||||
ParsingPackage::setAttributionsAreUserVisible,
|
||||
true
|
||||
),
|
||||
getSetByValue2(
|
||||
AndroidPackage::getOverlayables,
|
||||
PackageImpl::addOverlayable,
|
||||
"testOverlayableName" to "testActorName",
|
||||
transformGet = { "testOverlayableName" to it["testOverlayableName"] }
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getMetaData,
|
||||
PackageImpl::setMetaData,
|
||||
"testBundleKey" to "testBundleValue",
|
||||
transformGet = { "testBundleKey" to it?.getString("testBundleKey") },
|
||||
transformSet = { Bundle().apply { putString(it.first, it.second) } }
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getAttributions,
|
||||
PackageImpl::addAttribution,
|
||||
Triple("testTag", 13, listOf("testInherit")),
|
||||
transformGet = { it.singleOrNull()?.let { Triple(it.tag, it.label, it.inheritFrom) } },
|
||||
transformSet = { it?.let { ParsedAttribution(it.first, it.second, it.third) } }
|
||||
),
|
||||
getSetByValue2(
|
||||
AndroidPackage::getKeySetMapping,
|
||||
PackageImpl::addKeySet,
|
||||
"testKeySetName" to testKey(),
|
||||
transformGet = { "testKeySetName" to it["testKeySetName"]?.singleOrNull() },
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getPermissionGroups,
|
||||
PackageImpl::addPermissionGroup,
|
||||
"test.permission.GROUP",
|
||||
transformGet = { it.singleOrNull()?.name },
|
||||
transformSet = { ParsedPermissionGroup().apply { setName(it) } }
|
||||
),
|
||||
getSetByValue2(
|
||||
AndroidPackage::getPreferredActivityFilters,
|
||||
PackageImpl::addPreferredActivityFilter,
|
||||
"TestClassName" to ParsedIntentInfo().apply {
|
||||
addDataScheme("http")
|
||||
addDataAuthority("test.pm.server.android.com", null)
|
||||
},
|
||||
transformGet = { it.singleOrNull()?.let { it.first to it.second } },
|
||||
compare = { first, second ->
|
||||
equalBy(
|
||||
first, second,
|
||||
{ it.first },
|
||||
{ it.second.schemesIterator().asSequence().singleOrNull() },
|
||||
{ it.second.authoritiesIterator().asSequence().singleOrNull()?.host },
|
||||
)
|
||||
}
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getQueriesIntents,
|
||||
PackageImpl::addQueriesIntent,
|
||||
Intent(Intent.ACTION_VIEW, Uri.parse("https://test.pm.server.android.com")),
|
||||
transformGet = { it.singleOrNull() },
|
||||
compare = { first, second -> first?.filterEquals(second) },
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getRestrictUpdateHash,
|
||||
PackageImpl::setRestrictUpdateHash,
|
||||
byteArrayOf(0, 1, 2, 3, 4),
|
||||
compare = ByteArray::contentEquals
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getSigningDetails,
|
||||
PackageImpl::setSigningDetails,
|
||||
testKey(),
|
||||
transformGet = { it.publicKeys?.takeIf { it.size > 0 }?.valueAt(0) },
|
||||
transformSet = {
|
||||
SigningDetails(
|
||||
null,
|
||||
SigningDetails.SignatureSchemeVersion.UNKNOWN,
|
||||
ArraySet<PublicKey>().apply { add(it) },
|
||||
null
|
||||
)
|
||||
}
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getUsesStaticLibrariesCertDigests,
|
||||
PackageImpl::addUsesStaticLibraryCertDigests,
|
||||
arrayOf("testCertDigest"),
|
||||
transformGet = { it?.singleOrNull() },
|
||||
compare = Array<String?>?::contentEquals
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getActivities,
|
||||
PackageImpl::addActivity,
|
||||
"TestActivityName",
|
||||
transformGet = { it.singleOrNull()?.name.orEmpty() },
|
||||
transformSet = { ParsedActivity().apply { name = it }.withMimeGroups() }
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getReceivers,
|
||||
PackageImpl::addReceiver,
|
||||
"TestReceiverName",
|
||||
transformGet = { it.singleOrNull()?.name.orEmpty() },
|
||||
transformSet = { ParsedActivity().apply { name = it }.withMimeGroups() }
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getServices,
|
||||
PackageImpl::addService,
|
||||
"TestServiceName",
|
||||
transformGet = { it.singleOrNull()?.name.orEmpty() },
|
||||
transformSet = { ParsedService().apply { name = it }.withMimeGroups() }
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getProviders,
|
||||
PackageImpl::addProvider,
|
||||
"TestProviderName",
|
||||
transformGet = { it.singleOrNull()?.name.orEmpty() },
|
||||
transformSet = { ParsedProvider().apply { name = it }.withMimeGroups() }
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getInstrumentations,
|
||||
PackageImpl::addInstrumentation,
|
||||
"TestInstrumentationName",
|
||||
transformGet = { it.singleOrNull()?.name.orEmpty() },
|
||||
transformSet = { ParsedInstrumentation().apply { name = it } }
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getConfigPreferences,
|
||||
PackageImpl::addConfigPreference,
|
||||
testCounter++,
|
||||
transformGet = { it.singleOrNull()?.reqGlEsVersion ?: -1 },
|
||||
transformSet = { ConfigurationInfo().apply { reqGlEsVersion = it } }
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getFeatureGroups,
|
||||
PackageImpl::addFeatureGroup,
|
||||
"test.feature.GROUP",
|
||||
transformGet = { it.singleOrNull()?.features?.singleOrNull()?.name.orEmpty() },
|
||||
transformSet = {
|
||||
FeatureGroupInfo().apply {
|
||||
features = arrayOf(FeatureInfo().apply { name = it })
|
||||
}
|
||||
}
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getPermissions,
|
||||
PackageImpl::addPermission,
|
||||
"test.PERMISSION",
|
||||
transformGet = { it.singleOrNull()?.name.orEmpty() },
|
||||
transformSet = { ParsedPermission().apply { name = it } }
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getUsesPermissions,
|
||||
PackageImpl::addUsesPermission,
|
||||
"test.USES_PERMISSION",
|
||||
transformGet = {
|
||||
// Need to strip implicit permission, which calls addUsesPermission when added
|
||||
it.filterNot { it.name == "test.implicit.PERMISSION" }
|
||||
.singleOrNull()?.name.orEmpty()
|
||||
},
|
||||
transformSet = { ParsedUsesPermission(it, 0) }
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getReqFeatures,
|
||||
PackageImpl::addReqFeature,
|
||||
"test.feature.INFO",
|
||||
transformGet = { it.singleOrNull()?.name.orEmpty() },
|
||||
transformSet = { FeatureInfo().apply { name = it } }
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getMinExtensionVersions,
|
||||
PackageImpl::setMinExtensionVersions,
|
||||
SparseIntArray().apply { put(testCounter++, testCounter++) },
|
||||
compare = { first, second ->
|
||||
equalBy(
|
||||
first, second,
|
||||
{ it.size() },
|
||||
{ it.keyAt(0) },
|
||||
{ it.valueAt(0) },
|
||||
)
|
||||
}
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getProcesses,
|
||||
PackageImpl::setProcesses,
|
||||
mapOf("testProcess" to ParsedProcess().apply { name = "testProcessName" }),
|
||||
compare = { first, second ->
|
||||
equalBy(
|
||||
first, second,
|
||||
{ it["testProcess"]?.name },
|
||||
)
|
||||
}
|
||||
),
|
||||
getSetByValue(
|
||||
AndroidPackage::getProperties,
|
||||
PackageImpl::addProperty,
|
||||
PackageManager.Property(
|
||||
"testPropertyName",
|
||||
"testPropertyValue",
|
||||
"testPropertyClassName",
|
||||
"testPropertyPackageName"
|
||||
),
|
||||
transformGet = { it["testPropertyName"] },
|
||||
compare = { first, second ->
|
||||
equalBy(
|
||||
first, second,
|
||||
PackageManager.Property::getName,
|
||||
PackageManager.Property::getClassName,
|
||||
PackageManager.Property::getPackageName,
|
||||
PackageManager.Property::getString,
|
||||
)
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
override fun initialObject() = PackageImpl.forParsing(
|
||||
"com.example.test",
|
||||
"/test/test/base.apk",
|
||||
"/test/test",
|
||||
mockThrowOnUnmocked {
|
||||
whenever(getInteger(R.styleable.AndroidManifest_revisionCode, 0)) { 4 }
|
||||
whenever(getBoolean(R.styleable.AndroidManifest_isolatedSplits, false)) { true }
|
||||
|
||||
// Return invalid values here so that the getter/setter is tested properly
|
||||
whenever(getInteger(R.styleable.AndroidManifest_versionCode, 0)) { -1 }
|
||||
whenever(getInteger(R.styleable.AndroidManifest_versionCodeMajor, 0)) { -1 }
|
||||
whenever(
|
||||
getNonConfigurationString(
|
||||
R.styleable.AndroidManifest_versionName,
|
||||
0
|
||||
)
|
||||
) { "" }
|
||||
whenever(getInteger(R.styleable.AndroidManifest_compileSdkVersion, 0)) { 31 }
|
||||
whenever(
|
||||
getNonConfigurationString(
|
||||
R.styleable.AndroidManifest_compileSdkVersionCodename,
|
||||
0
|
||||
)
|
||||
) { "" }
|
||||
},
|
||||
true
|
||||
)
|
||||
.asSplit(
|
||||
arrayOf("testSplitNameZero", "testSplitNameOne"),
|
||||
arrayOf("/test/testSplitZero.apk", "/test/testSplitOne.apk"),
|
||||
intArrayOf(10, 11),
|
||||
SparseArray<IntArray>().apply {
|
||||
put(0, intArrayOf(-1))
|
||||
put(1, intArrayOf(0))
|
||||
}
|
||||
)
|
||||
.setSplitHasCode(0, true)
|
||||
.setSplitHasCode(1, false)
|
||||
.setSplitClassLoaderName(0, "testSplitClassLoaderNameZero")
|
||||
.setSplitClassLoaderName(1, "testSplitClassLoaderNameOne")
|
||||
|
||||
override fun extraAssertions(before: Parcelable, after: Parcelable) {
|
||||
super.extraAssertions(before, after)
|
||||
after as PackageImpl
|
||||
expect.that(after.manifestPackageName).isEqualTo("com.example.test")
|
||||
expect.that(after.isCoreApp).isTrue()
|
||||
expect.that(after.isIsolatedSplitLoading).isEqualTo(true)
|
||||
expect.that(after.longVersionCode).isEqualTo(38654705667)
|
||||
expect.that(after.requestedPermissions)
|
||||
.containsExactlyElementsIn(after.usesPermissions.map { it.name })
|
||||
.inOrder()
|
||||
|
||||
expect.that(after.mimeGroups).containsExactly(
|
||||
"TestActivityName/mimeGroup",
|
||||
"TestReceiverName/mimeGroup",
|
||||
"TestServiceName/mimeGroup",
|
||||
"TestProviderName/mimeGroup"
|
||||
)
|
||||
|
||||
expect.that(after.splitNames).asList()
|
||||
.containsExactly("testSplitNameZero", "testSplitNameOne")
|
||||
.inOrder()
|
||||
expect.that(after.splitCodePaths).asList()
|
||||
.containsExactly("/test/testSplitZero.apk", "/test/testSplitOne.apk")
|
||||
.inOrder()
|
||||
expect.that(after.splitRevisionCodes).asList()
|
||||
.containsExactly(10, 11)
|
||||
.inOrder()
|
||||
expect.that(after.splitFlags).asList()
|
||||
.containsExactly(ApplicationInfo.FLAG_HAS_CODE, 0)
|
||||
.inOrder()
|
||||
expect.that(after.splitClassLoaderNames).asList()
|
||||
.containsExactly("testSplitClassLoaderNameZero", "testSplitClassLoaderNameOne")
|
||||
.inOrder()
|
||||
|
||||
expect.that(after.splitDependencies).isNotNull()
|
||||
after.splitDependencies?.let {
|
||||
expect.that(it.size()).isEqualTo(2)
|
||||
expect.that(it.get(0)).asList().containsExactly(-1)
|
||||
expect.that(it.get(1)).asList().containsExactly(0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun testKey() = KeyPairGenerator.getInstance("RSA")
|
||||
.generateKeyPair()
|
||||
.public
|
||||
|
||||
private fun <T : ParsedComponent> T.withMimeGroups() = apply {
|
||||
val componentName = name
|
||||
addIntent(ParsedIntentInfo().apply {
|
||||
addMimeGroup("$componentName/mimeGroup")
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,413 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.parsing.parcelling
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import com.android.server.pm.test.util.IgnoreableExpect
|
||||
import com.google.common.truth.Expect
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TestRule
|
||||
import java.util.Objects
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KFunction
|
||||
import kotlin.reflect.KFunction1
|
||||
import kotlin.reflect.KFunction2
|
||||
import kotlin.reflect.KFunction3
|
||||
import kotlin.reflect.KVisibility
|
||||
import kotlin.reflect.full.allSuperclasses
|
||||
import kotlin.reflect.full.createInstance
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
import kotlin.reflect.full.memberFunctions
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.full.staticProperties
|
||||
import kotlin.reflect.jvm.jvmErasure
|
||||
|
||||
|
||||
@ExperimentalContracts
|
||||
abstract class ParcelableComponentTest(
|
||||
private val getterType: KClass<*>,
|
||||
private val setterType: KClass<out Parcelable>
|
||||
) {
|
||||
|
||||
companion object {
|
||||
private val DEFAULT_EXCLUDED = listOf(
|
||||
// Java
|
||||
"toString",
|
||||
"equals",
|
||||
"hashCode",
|
||||
// Parcelable
|
||||
"getStability",
|
||||
"describeContents",
|
||||
"writeToParcel",
|
||||
// @DataClass
|
||||
"__metadata"
|
||||
)
|
||||
}
|
||||
|
||||
internal val ignoreableExpect = IgnoreableExpect()
|
||||
|
||||
// Hides internal type
|
||||
@get:Rule
|
||||
val ignoreableAsTestRule: TestRule = ignoreableExpect
|
||||
|
||||
val expect: Expect
|
||||
get() = ignoreableExpect.expect
|
||||
|
||||
protected var testCounter = 1
|
||||
|
||||
protected abstract val defaultImpl: Any
|
||||
protected abstract val creator: Parcelable.Creator<out Parcelable>
|
||||
|
||||
protected open val excludedMethods: Collection<String> = emptyList()
|
||||
|
||||
protected abstract val baseParams: Collection<KFunction1<*, Any?>>
|
||||
|
||||
private val getters = getterType.memberFunctions
|
||||
.filterNot { DEFAULT_EXCLUDED.contains(it.name) }
|
||||
|
||||
private val setters = setterType.memberFunctions
|
||||
.filterNot { DEFAULT_EXCLUDED.contains(it.name) }
|
||||
|
||||
constructor(kClass: KClass<out Parcelable>) : this(kClass, kClass)
|
||||
|
||||
@Before
|
||||
fun checkNoPublicFields() {
|
||||
// Fields are not currently testable, and the idea is to enforce interface access for
|
||||
// immutability purposes, so disallow any public fields from existing.
|
||||
expect.that(getterType.memberProperties.filter { it.visibility == KVisibility.PUBLIC }
|
||||
.filterNot { DEFAULT_EXCLUDED.contains(it.name) })
|
||||
.isEmpty()
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun <ObjectType, ReturnType> buildParams(
|
||||
getFunction: KFunction1<ObjectType, ReturnType>,
|
||||
): Param? {
|
||||
return buildParams<ObjectType, ReturnType, ReturnType, ReturnType>(
|
||||
getFunction,
|
||||
autoValue(getFunction) as ReturnType ?: return null
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun <ObjectType, ReturnType, SetType : Any?, CompareType : Any?> buildParams(
|
||||
getFunction: KFunction1<ObjectType, ReturnType>,
|
||||
value: SetType,
|
||||
): Param? {
|
||||
return getSetByValue<ObjectType, ReturnType, SetType, Any?>(
|
||||
getFunction,
|
||||
findSetFunction(getFunction) ?: return null,
|
||||
value
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun <ObjectType, ReturnType> findSetFunction(
|
||||
getFunction: KFunction1<ObjectType, ReturnType>
|
||||
): KFunction2<ObjectType, ReturnType, Any?>? {
|
||||
val getFunctionName = getFunction.name
|
||||
val prefix = when {
|
||||
getFunctionName.startsWith("get") -> "get"
|
||||
getFunctionName.startsWith("is") -> "is"
|
||||
getFunctionName.startsWith("has") -> "has"
|
||||
else -> throw IllegalArgumentException("Unsupported method name $getFunctionName")
|
||||
}
|
||||
val setFunctionName = "set" + getFunctionName.removePrefix(prefix)
|
||||
val setFunction = setters.filter { it.name == setFunctionName }
|
||||
.minByOrNull { it.parameters.size }
|
||||
|
||||
if (setFunction == null) {
|
||||
expect.withMessage("$getFunctionName does not have corresponding $setFunctionName")
|
||||
.fail()
|
||||
return null
|
||||
}
|
||||
|
||||
return setFunction as KFunction2<ObjectType, ReturnType, Any?>
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun <ObjectType, ReturnType, SetType> findAddFunction(
|
||||
getFunction: KFunction1<ObjectType, ReturnType>
|
||||
): KFunction2<ObjectType, SetType, Any?>? {
|
||||
val getFunctionName = getFunction.name
|
||||
if (!getFunctionName.startsWith("get")) {
|
||||
throw IllegalArgumentException("Unsupported method name $getFunctionName")
|
||||
}
|
||||
|
||||
val setFunctionName = "add" + getFunctionName.removePrefix("get").run {
|
||||
// Remove plurality
|
||||
when {
|
||||
endsWith("ies") -> "${removeSuffix("ies")}y"
|
||||
endsWith("s") -> removeSuffix("s")
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
val setFunction = setters.filter { it.name == setFunctionName }
|
||||
.minByOrNull { it.parameters.size }
|
||||
|
||||
if (setFunction == null) {
|
||||
expect.withMessage("$getFunctionName does not have corresponding $setFunctionName")
|
||||
.fail()
|
||||
return null
|
||||
}
|
||||
|
||||
return setFunction as KFunction2<ObjectType, SetType, Any?>
|
||||
}
|
||||
|
||||
protected fun <ObjectType, ReturnType> getter(
|
||||
getFunction: KFunction1<ObjectType, ReturnType>,
|
||||
valueToSet: ReturnType
|
||||
) = buildParams<ObjectType, ReturnType, ReturnType, ReturnType>(getFunction, valueToSet)
|
||||
|
||||
protected fun <ObjectType, ReturnType, SetType : Any?, CompareType : Any?> getter(
|
||||
getFunction: KFunction1<ObjectType, ReturnType>,
|
||||
expectedValue: CompareType,
|
||||
valueToSet: SetType
|
||||
): Param? {
|
||||
return getSetByValue(
|
||||
getFunction,
|
||||
findSetFunction(getFunction) ?: return null,
|
||||
value = expectedValue,
|
||||
transformSet = { valueToSet }
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
protected fun <ObjectType, ReturnType> adder(
|
||||
getFunction: KFunction1<ObjectType, ReturnType>,
|
||||
value: ReturnType,
|
||||
): Param? {
|
||||
return getSetByValue(
|
||||
getFunction,
|
||||
findAddFunction<ObjectType, Any?, ReturnType>(getFunction) ?: return null,
|
||||
value,
|
||||
transformGet = {
|
||||
// Primitive arrays don't implement Iterable, so cast manually
|
||||
when (it) {
|
||||
is BooleanArray -> it.singleOrNull()
|
||||
is IntArray -> it.singleOrNull()
|
||||
is LongArray -> it.singleOrNull()
|
||||
is Iterable<*> -> it.singleOrNull()
|
||||
else -> null
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to provide custom getter and setter logic for values which are not simple primitives
|
||||
* or cannot be directly compared using [Objects.equals].
|
||||
*
|
||||
* @param getFunction the getter function which will be called and marked as tested
|
||||
* @param setFunction the setter function which will be called and marked as tested
|
||||
* @param value the value for comparison through the parcel-unparcel cycle, which can be
|
||||
* anything, like the [String] ID of an inner object
|
||||
* @param transformGet the function to transform the result of [getFunction] into [value]
|
||||
* @param transformSet the function to transform [value] into an input for [setFunction]
|
||||
* @param compare the function that compares the pre/post-parcel [value] objects
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
protected fun <ObjectType, ReturnType, SetType : Any?, CompareType : Any?> getSetByValue(
|
||||
getFunction: KFunction1<ObjectType, ReturnType>,
|
||||
setFunction: KFunction2<ObjectType, SetType, Any?>,
|
||||
value: CompareType,
|
||||
transformGet: (ReturnType) -> CompareType = { it as CompareType },
|
||||
transformSet: (CompareType) -> SetType = { it as SetType },
|
||||
compare: (CompareType, CompareType) -> Boolean? = Objects::equals
|
||||
) = Param(
|
||||
getFunction.name,
|
||||
{ transformGet(getFunction.call(it as ObjectType)) },
|
||||
setFunction.name,
|
||||
{ setFunction.call(it.first() as ObjectType, transformSet(it[1] as CompareType)) },
|
||||
{ value },
|
||||
{ first, second -> compare(first as CompareType, second as CompareType) == true }
|
||||
)
|
||||
|
||||
/**
|
||||
* Variant of [getSetByValue] that allows specifying a [setFunction] with 2 inputs.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
protected fun <ObjectType, ReturnType, SetType1 : Any?, SetType2 : Any?, CompareType : Any?>
|
||||
getSetByValue2(
|
||||
getFunction: KFunction1<ObjectType, ReturnType>,
|
||||
setFunction: KFunction3<ObjectType, SetType1, SetType2, Any>,
|
||||
value: CompareType,
|
||||
transformGet: (ReturnType) -> CompareType = { it as CompareType },
|
||||
transformSet: (CompareType) -> Pair<SetType1, SetType2> =
|
||||
{ it as Pair<SetType1, SetType2> },
|
||||
compare: (CompareType, CompareType) -> Boolean = Objects::equals
|
||||
) = Param(
|
||||
getFunction.name,
|
||||
{ transformGet(getFunction.call(it as ObjectType)) },
|
||||
setFunction.name,
|
||||
{
|
||||
val pair = transformSet(it[1] as CompareType)
|
||||
setFunction.call(it.first() as ObjectType, pair.first, pair.second)
|
||||
},
|
||||
{ value },
|
||||
{ first, second -> compare(first as CompareType, second as CompareType) }
|
||||
)
|
||||
|
||||
protected fun autoValue(getFunction: KFunction<*>) = when (getFunction.returnType.jvmErasure) {
|
||||
Boolean::class -> (getFunction.call(defaultImpl) as Boolean?)?.not() ?: true
|
||||
CharSequence::class,
|
||||
String::class -> getFunction.name + "TEST"
|
||||
Int::class -> testCounter++
|
||||
Long::class -> (testCounter++).toLong()
|
||||
Float::class -> (testCounter++).toFloat()
|
||||
else -> {
|
||||
expect.withMessage("${getFunction.name} needs to provide value").fail()
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies two instances are equivalent via a series of properties. For use when a public API
|
||||
* class has not implemented equals.
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
protected fun <T : Any> equalBy(
|
||||
first: T?,
|
||||
second: T?,
|
||||
vararg properties: (T) -> Any?
|
||||
) = properties.all { property ->
|
||||
first?.let { property(it) } == second?.let { property(it) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun valueComparison() {
|
||||
val params = baseParams.mapNotNull(::buildParams) + extraParams().filterNotNull()
|
||||
val before = initialObject()
|
||||
|
||||
params.forEach { it.setFunction(arrayOf(before, it.value())) }
|
||||
|
||||
val parcel = Parcel.obtain()
|
||||
writeToParcel(parcel, before)
|
||||
|
||||
val dataSize = parcel.dataSize()
|
||||
|
||||
parcel.setDataPosition(0)
|
||||
|
||||
val after = creator.createFromParcel(parcel)
|
||||
|
||||
expect.withMessage("Mismatched write and read data sizes")
|
||||
.that(parcel.dataPosition())
|
||||
.isEqualTo(dataSize)
|
||||
|
||||
parcel.recycle()
|
||||
|
||||
runAssertions(params, before, after)
|
||||
}
|
||||
|
||||
@Test
|
||||
open fun parcellingSize() {
|
||||
val parcelOne = Parcel.obtain()
|
||||
writeToParcel(parcelOne, initialObject())
|
||||
|
||||
val parcelTwo = Parcel.obtain()
|
||||
initialObject().writeToParcel(parcelTwo, 0)
|
||||
|
||||
val superDataSizes = setterType.allSuperclasses
|
||||
.filter { it.isSubclassOf(Parcelable::class) }
|
||||
.mapNotNull { it.memberFunctions.find { it.name == "writeToParcel" } }
|
||||
.filter { it.isFinal }
|
||||
.map {
|
||||
val parcel = Parcel.obtain()
|
||||
initialObject().writeToParcel(parcel, 0)
|
||||
parcel.dataSize().also { parcel.recycle() }
|
||||
}
|
||||
|
||||
if ((superDataSizes + parcelOne.dataSize() + parcelTwo.dataSize()).distinct().size != 1) {
|
||||
listOf(getterType, setterType).distinct().forEach {
|
||||
val creatorProperties = it.staticProperties.filter { it.name == "CREATOR" }
|
||||
if (creatorProperties.size > 1) {
|
||||
expect.withMessage(
|
||||
"Multiple matching CREATOR fields found for" +
|
||||
it.qualifiedName
|
||||
)
|
||||
.that(creatorProperties)
|
||||
.hasSize(1)
|
||||
} else {
|
||||
val creator = creatorProperties.single().get()
|
||||
if (creator !is Parcelable.Creator<*>) {
|
||||
expect.that(creator).isInstanceOf(Parcelable.Creator::class.java)
|
||||
return
|
||||
}
|
||||
|
||||
parcelTwo.setDataPosition(0)
|
||||
val parcelable = creator.createFromParcel(parcelTwo)
|
||||
if (parcelable::class.isSubclassOf(setterType)) {
|
||||
expect.withMessage(
|
||||
"${it.qualifiedName} which does not safely override writeToParcel " +
|
||||
"cannot contain a subclass CREATOR field"
|
||||
)
|
||||
.fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parcelOne.recycle()
|
||||
parcelTwo.recycle()
|
||||
}
|
||||
|
||||
private fun runAssertions(params: List<Param>, before: Parcelable, after: Parcelable) {
|
||||
params.forEach {
|
||||
val actual = it.getFunction(after)
|
||||
val expected = it.value()
|
||||
val equal = it.compare(actual, expected)
|
||||
expect.withMessage("${it.getFunctionName} was $actual, expected $expected")
|
||||
.that(equal)
|
||||
.isTrue()
|
||||
}
|
||||
|
||||
extraAssertions(before, after)
|
||||
|
||||
// TODO: Handle method overloads?
|
||||
val expectedFunctions = (getters.map { it.name }
|
||||
+ setters.map { it.name }
|
||||
- excludedMethods)
|
||||
.distinct()
|
||||
|
||||
val allTestedFunctions = params.flatMap {
|
||||
listOfNotNull(it.getFunctionName, it.setFunctionName)
|
||||
}
|
||||
expect.that(allTestedFunctions).containsExactlyElementsIn(expectedFunctions)
|
||||
}
|
||||
|
||||
open fun extraParams(): Collection<Param?> = emptyList()
|
||||
|
||||
open fun initialObject(): Parcelable = setterType.createInstance()
|
||||
|
||||
open fun extraAssertions(before: Parcelable, after: Parcelable) {}
|
||||
|
||||
open fun writeToParcel(parcel: Parcel, value: Parcelable) = value.writeToParcel(parcel, 0)
|
||||
|
||||
data class Param(
|
||||
val getFunctionName: String,
|
||||
val getFunction: (Any?) -> Any?,
|
||||
val setFunctionName: String?,
|
||||
val setFunction: (Array<Any?>) -> Unit,
|
||||
val value: () -> Any?,
|
||||
val compare: (Any?, Any?) -> Boolean = Objects::equals
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.parsing.parcelling
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import com.android.server.pm.test.parsing.parcelling.java.TestSubWithCreator
|
||||
import com.android.server.pm.test.parsing.parcelling.java.TestSuperClass
|
||||
import org.junit.Test
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
|
||||
/**
|
||||
* Verifies the failing side of [ParcelableCreatorValidTest]. The sole difference is the addition
|
||||
* of [TestSubWithCreator.CREATOR].
|
||||
*/
|
||||
@ExperimentalContracts
|
||||
class ParcelableCreatorInvalidTest :
|
||||
ParcelableComponentTest(TestSuperClass::class, TestSubWithCreator::class) {
|
||||
|
||||
override val defaultImpl = TestSubWithCreator()
|
||||
|
||||
override val creator = object : Parcelable.Creator<Parcelable> {
|
||||
override fun createFromParcel(source: Parcel) = TestSubWithCreator(source)
|
||||
override fun newArray(size: Int) = Array<TestSubWithCreator?>(size) { null }
|
||||
}
|
||||
|
||||
override val excludedMethods = listOf("writeSubToParcel")
|
||||
|
||||
override val baseParams = listOf(TestSuperClass::getSuperString)
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, value: Parcelable) {
|
||||
(value as TestSubWithCreator).writeSubToParcel(parcel, 0)
|
||||
}
|
||||
|
||||
@Test
|
||||
override fun parcellingSize() {
|
||||
super.parcellingSize()
|
||||
if (expect.hasFailures()) {
|
||||
// This is a hack to ignore an expected failure result. Doing it this way, rather than
|
||||
// adding a switch in the test itself, prevents it from accidentally passing through a
|
||||
// programming error.
|
||||
ignoreableExpect.ignore()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.parsing.parcelling
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import com.android.server.pm.test.parsing.parcelling.java.TestSubWithoutCreator
|
||||
import com.android.server.pm.test.parsing.parcelling.java.TestSuperClass
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
|
||||
/**
|
||||
* Tests the [Parcelable] CREATOR verification by using a mock object with known differences to
|
||||
* ensure that the method succeeds/fails.
|
||||
*/
|
||||
@ExperimentalContracts
|
||||
class ParcelableCreatorValidTest :
|
||||
ParcelableComponentTest(TestSuperClass::class, TestSubWithoutCreator::class) {
|
||||
|
||||
override val defaultImpl = TestSubWithoutCreator()
|
||||
|
||||
override val creator = object : Parcelable.Creator<Parcelable> {
|
||||
override fun createFromParcel(source: Parcel) = TestSubWithoutCreator(source)
|
||||
override fun newArray(size: Int) = Array<TestSubWithoutCreator?>(size) { null }
|
||||
}
|
||||
|
||||
override val excludedMethods = listOf("writeSubToParcel")
|
||||
|
||||
override val baseParams = listOf(TestSuperClass::getSuperString)
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, value: Parcelable) {
|
||||
(value as TestSubWithoutCreator).writeSubToParcel(parcel, 0)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.parsing.parcelling
|
||||
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.pm.parsing.component.ParsedActivity
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
|
||||
@ExperimentalContracts
|
||||
class ParsedActivityTest : ParsedMainComponentTest(ParsedActivity::class) {
|
||||
|
||||
override val defaultImpl = ParsedActivity()
|
||||
override val creator = ParsedActivity.CREATOR
|
||||
|
||||
override val mainComponentSubclassBaseParams = listOf(
|
||||
ParsedActivity::getPermission,
|
||||
ParsedActivity::getColorMode,
|
||||
ParsedActivity::getConfigChanges,
|
||||
ParsedActivity::getDocumentLaunchMode,
|
||||
ParsedActivity::getLaunchMode,
|
||||
ParsedActivity::getLockTaskLaunchMode,
|
||||
ParsedActivity::getMaxAspectRatio,
|
||||
ParsedActivity::getMaxRecents,
|
||||
ParsedActivity::getMinAspectRatio,
|
||||
ParsedActivity::getParentActivityName,
|
||||
ParsedActivity::getPersistableMode,
|
||||
ParsedActivity::getPrivateFlags,
|
||||
ParsedActivity::getRequestedVrComponent,
|
||||
ParsedActivity::getResizeMode,
|
||||
ParsedActivity::getRotationAnimation,
|
||||
ParsedActivity::getScreenOrientation,
|
||||
ParsedActivity::getSoftInputMode,
|
||||
ParsedActivity::getTargetActivity,
|
||||
ParsedActivity::getTaskAffinity,
|
||||
ParsedActivity::getTheme,
|
||||
ParsedActivity::getUiOptions,
|
||||
ParsedActivity::isSupportsSizeChanges,
|
||||
)
|
||||
|
||||
override fun mainComponentSubclassExtraParams() = listOf(
|
||||
getSetByValue(
|
||||
ParsedActivity::getWindowLayout,
|
||||
ParsedActivity::setWindowLayout,
|
||||
ActivityInfo.WindowLayout(1, 1f, 2, 1f, 3, 4, 5),
|
||||
compare = { first, second ->
|
||||
equalBy(
|
||||
first, second,
|
||||
ActivityInfo.WindowLayout::width,
|
||||
ActivityInfo.WindowLayout::widthFraction,
|
||||
ActivityInfo.WindowLayout::height,
|
||||
ActivityInfo.WindowLayout::heightFraction,
|
||||
ActivityInfo.WindowLayout::gravity,
|
||||
ActivityInfo.WindowLayout::minWidth,
|
||||
ActivityInfo.WindowLayout::minHeight
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.parsing.parcelling
|
||||
|
||||
import android.content.pm.parsing.component.ParsedAttribution
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
|
||||
@ExperimentalContracts
|
||||
class ParsedAttributionTest : ParcelableComponentTest(ParsedAttribution::class) {
|
||||
|
||||
override val defaultImpl = ParsedAttribution("", 0, emptyList())
|
||||
override val creator = ParsedAttribution.CREATOR
|
||||
|
||||
override val baseParams = listOf(
|
||||
ParsedAttribution::getTag,
|
||||
ParsedAttribution::getLabel,
|
||||
)
|
||||
|
||||
override fun extraParams() = listOf(
|
||||
getter(ParsedAttribution::getInheritFrom, listOf("testInheritFrom"))
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.parsing.parcelling
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.parsing.component.ParsedComponent
|
||||
import android.content.pm.parsing.component.ParsedIntentInfo
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KFunction1
|
||||
|
||||
@ExperimentalContracts
|
||||
abstract class ParsedComponentTest(kClass: KClass<out Parcelable>) :
|
||||
ParcelableComponentTest(kClass) {
|
||||
|
||||
final override val excludedMethods
|
||||
get() = subclassExcludedMethods + listOf(
|
||||
// Method aliases/utilities
|
||||
"getClassName",
|
||||
"getComponentName",
|
||||
"setProperties" // Tested though addProperty
|
||||
)
|
||||
|
||||
open val subclassExcludedMethods: Collection<String> = emptyList()
|
||||
|
||||
final override val baseParams
|
||||
get() = subclassBaseParams + listOf(
|
||||
ParsedComponent::getBanner,
|
||||
ParsedComponent::getDescriptionRes,
|
||||
ParsedComponent::getFlags,
|
||||
ParsedComponent::getIcon,
|
||||
ParsedComponent::getLabelRes,
|
||||
ParsedComponent::getLogo,
|
||||
ParsedComponent::getName,
|
||||
ParsedComponent::getNonLocalizedLabel,
|
||||
ParsedComponent::getPackageName,
|
||||
)
|
||||
|
||||
abstract val subclassBaseParams: Collection<KFunction1<*, Any?>>
|
||||
|
||||
final override fun extraParams() = subclassExtraParams() + listOf(
|
||||
getSetByValue(
|
||||
ParsedComponent::getIntents,
|
||||
ParsedComponent::addIntent,
|
||||
"TestLabel",
|
||||
transformGet = { it.singleOrNull()?.nonLocalizedLabel },
|
||||
transformSet = { ParsedIntentInfo().setNonLocalizedLabel(it) },
|
||||
),
|
||||
getSetByValue(
|
||||
ParsedComponent::getProperties,
|
||||
ParsedComponent::addProperty,
|
||||
PackageManager.Property(
|
||||
"testPropertyName",
|
||||
"testPropertyValue",
|
||||
"testPropertyClassName",
|
||||
"testPropertyPackageName"
|
||||
),
|
||||
transformGet = { it["testPropertyName"] },
|
||||
compare = { first, second ->
|
||||
equalBy(
|
||||
first, second,
|
||||
PackageManager.Property::getName,
|
||||
PackageManager.Property::getClassName,
|
||||
PackageManager.Property::getPackageName,
|
||||
PackageManager.Property::getString,
|
||||
)
|
||||
}
|
||||
),
|
||||
getSetByValue(
|
||||
ParsedComponent::getMetaData,
|
||||
ParsedComponent::setMetaData,
|
||||
"testBundleKey" to "testBundleValue",
|
||||
transformGet = { "testBundleKey" to it?.getString("testBundleKey") },
|
||||
transformSet = { Bundle().apply { putString(it.first, it.second) } }
|
||||
),
|
||||
)
|
||||
|
||||
open fun subclassExtraParams(): Collection<Param?> = emptyList()
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.parsing.parcelling
|
||||
|
||||
import android.content.pm.parsing.component.ParsedInstrumentation
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
|
||||
@ExperimentalContracts
|
||||
class ParsedInstrumentationTest : ParsedComponentTest(ParsedInstrumentation::class) {
|
||||
|
||||
override val defaultImpl = ParsedInstrumentation()
|
||||
override val creator = ParsedInstrumentation.CREATOR
|
||||
|
||||
override val subclassBaseParams = listOf(
|
||||
ParsedInstrumentation::getTargetPackage,
|
||||
ParsedInstrumentation::getTargetProcesses,
|
||||
ParsedInstrumentation::isFunctionalTest,
|
||||
ParsedInstrumentation::isHandleProfiling,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.parsing.parcelling
|
||||
|
||||
import android.content.pm.parsing.component.ParsedIntentInfo
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import android.os.PatternMatcher
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
|
||||
@ExperimentalContracts
|
||||
class ParsedIntentInfoTest : ParcelableComponentTest(ParsedIntentInfo::class) {
|
||||
|
||||
override val defaultImpl = ParsedIntentInfo()
|
||||
|
||||
override val creator = object : Parcelable.Creator<ParsedIntentInfo> {
|
||||
override fun createFromParcel(source: Parcel) = ParsedIntentInfo(source)
|
||||
override fun newArray(size: Int) = Array<ParsedIntentInfo?>(size) { null }
|
||||
}
|
||||
|
||||
override val excludedMethods = listOf(
|
||||
// Used to parcel
|
||||
"writeIntentInfoToParcel",
|
||||
// All remaining IntentFilter methods, which are out of scope
|
||||
"hasDataPath",
|
||||
"hasDataSchemeSpecificPart",
|
||||
"matchAction",
|
||||
"matchData",
|
||||
"actionsIterator",
|
||||
"addAction",
|
||||
"addCategory",
|
||||
"addDataAuthority",
|
||||
"addDataPath",
|
||||
"addDataScheme",
|
||||
"addDataSchemeSpecificPart",
|
||||
"addDataType",
|
||||
"addDynamicDataType",
|
||||
"addMimeGroup",
|
||||
"asPredicate",
|
||||
"asPredicateWithTypeResolution",
|
||||
"authoritiesIterator",
|
||||
"categoriesIterator",
|
||||
"clearDynamicDataTypes",
|
||||
"countActions",
|
||||
"countCategories",
|
||||
"countDataAuthorities",
|
||||
"countDataPaths",
|
||||
"countDataSchemeSpecificParts",
|
||||
"countDataSchemes",
|
||||
"countDataTypes",
|
||||
"countMimeGroups",
|
||||
"countStaticDataTypes",
|
||||
"dataTypes",
|
||||
"debugCheck",
|
||||
"dump",
|
||||
"dumpDebug",
|
||||
"getAction",
|
||||
"getAutoVerify",
|
||||
"getCategory",
|
||||
"getDataAuthority",
|
||||
"getDataPath",
|
||||
"getDataScheme",
|
||||
"getDataSchemeSpecificPart",
|
||||
"getDataType",
|
||||
"getHosts",
|
||||
"getHostsList",
|
||||
"getMimeGroup",
|
||||
"getOrder",
|
||||
"getPriority",
|
||||
"getVisibilityToInstantApp",
|
||||
"handleAllWebDataURI",
|
||||
"handlesWebUris",
|
||||
"hasAction",
|
||||
"hasCategory",
|
||||
"hasDataAuthority",
|
||||
"hasDataScheme",
|
||||
"hasDataType",
|
||||
"hasExactDataType",
|
||||
"hasExactDynamicDataType",
|
||||
"hasExactStaticDataType",
|
||||
"hasMimeGroup",
|
||||
"isExplicitlyVisibleToInstantApp",
|
||||
"isImplicitlyVisibleToInstantApp",
|
||||
"isVerified",
|
||||
"isVisibleToInstantApp",
|
||||
"match",
|
||||
"matchCategories",
|
||||
"matchDataAuthority",
|
||||
"mimeGroupsIterator",
|
||||
"needsVerification",
|
||||
"pathsIterator",
|
||||
"readFromXml",
|
||||
"schemeSpecificPartsIterator",
|
||||
"schemesIterator",
|
||||
"setAutoVerify",
|
||||
"setOrder",
|
||||
"setPriority",
|
||||
"setVerified",
|
||||
"setVisibilityToInstantApp",
|
||||
"typesIterator",
|
||||
"writeToXml",
|
||||
)
|
||||
|
||||
override val baseParams = listOf(
|
||||
ParsedIntentInfo::getIcon,
|
||||
ParsedIntentInfo::getLabelRes,
|
||||
ParsedIntentInfo::isHasDefault,
|
||||
ParsedIntentInfo::getNonLocalizedLabel,
|
||||
)
|
||||
|
||||
override fun initialObject() = ParsedIntentInfo().apply {
|
||||
addAction("test.ACTION")
|
||||
addDataAuthority("testAuthority", "404")
|
||||
addCategory("test.CATEGORY")
|
||||
addMimeGroup("testMime")
|
||||
addDataPath("testPath", PatternMatcher.PATTERN_LITERAL)
|
||||
}
|
||||
|
||||
override fun extraAssertions(before: Parcelable, after: Parcelable) {
|
||||
super.extraAssertions(before, after)
|
||||
after as ParsedIntentInfo
|
||||
expect.that(after.actionsIterator().asSequence().singleOrNull())
|
||||
.isEqualTo("test.ACTION")
|
||||
|
||||
val authority = after.authoritiesIterator().asSequence().singleOrNull()
|
||||
expect.that(authority?.host).isEqualTo("testAuthority")
|
||||
expect.that(authority?.port).isEqualTo(404)
|
||||
|
||||
expect.that(after.categoriesIterator().asSequence().singleOrNull())
|
||||
.isEqualTo("test.CATEGORY")
|
||||
expect.that(after.mimeGroupsIterator().asSequence().singleOrNull())
|
||||
.isEqualTo("testMime")
|
||||
expect.that(after.hasDataPath("testPath")).isTrue()
|
||||
}
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, value: Parcelable) =
|
||||
ParsedIntentInfo.PARCELER.parcel(value as ParsedIntentInfo, parcel, 0)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.parsing.parcelling
|
||||
|
||||
import android.content.pm.parsing.component.ParsedMainComponent
|
||||
import android.content.pm.parsing.component.ParsedService
|
||||
import android.os.Parcelable
|
||||
import java.util.Arrays
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KFunction1
|
||||
|
||||
@ExperimentalContracts
|
||||
abstract class ParsedMainComponentTest(kClass: KClass<out Parcelable>) :
|
||||
ParsedComponentTest(kClass) {
|
||||
|
||||
final override val subclassBaseParams
|
||||
get() = mainComponentSubclassBaseParams + listOf(
|
||||
ParsedMainComponent::getOrder,
|
||||
ParsedMainComponent::getProcessName,
|
||||
ParsedMainComponent::getSplitName,
|
||||
ParsedMainComponent::isDirectBootAware,
|
||||
ParsedMainComponent::isEnabled,
|
||||
ParsedMainComponent::isExported,
|
||||
)
|
||||
|
||||
abstract val mainComponentSubclassBaseParams: Collection<KFunction1<*, Any?>>
|
||||
|
||||
final override fun subclassExtraParams() = mainComponentSubclassExtraParams() + listOf(
|
||||
getSetByValue(
|
||||
ParsedService::getAttributionTags,
|
||||
ParsedService::setAttributionTags,
|
||||
arrayOf("testAttributionTag"),
|
||||
compare = Arrays::equals
|
||||
),
|
||||
)
|
||||
|
||||
open fun mainComponentSubclassExtraParams(): Collection<Param?> = emptyList()
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.parsing.parcelling
|
||||
|
||||
import android.content.pm.parsing.component.ParsedPermissionGroup
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
|
||||
@ExperimentalContracts
|
||||
class ParsedPermissionGroupTest : ParsedComponentTest(ParsedPermissionGroup::class) {
|
||||
|
||||
override val defaultImpl = ParsedPermissionGroup()
|
||||
override val creator = ParsedPermissionGroup.CREATOR
|
||||
|
||||
override val subclassBaseParams = listOf(
|
||||
ParsedPermissionGroup::getRequestDetailResourceId,
|
||||
ParsedPermissionGroup::getBackgroundRequestDetailResourceId,
|
||||
ParsedPermissionGroup::getBackgroundRequestResourceId,
|
||||
ParsedPermissionGroup::getRequestRes,
|
||||
ParsedPermissionGroup::getPriority,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.parsing.parcelling
|
||||
|
||||
import android.content.pm.parsing.component.ParsedPermission
|
||||
import android.content.pm.parsing.component.ParsedPermissionGroup
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
|
||||
@ExperimentalContracts
|
||||
class ParsedPermissionTest : ParsedComponentTest(ParsedPermission::class) {
|
||||
|
||||
override val defaultImpl = ParsedPermission()
|
||||
override val creator = ParsedPermission.CREATOR
|
||||
|
||||
override val subclassExcludedMethods = listOf(
|
||||
// Utility methods
|
||||
"isAppOp",
|
||||
"isRuntime",
|
||||
"getProtection",
|
||||
"getProtectionFlags",
|
||||
"calculateFootprint",
|
||||
"setKnownCert", // Tested through setKnownCerts
|
||||
)
|
||||
override val subclassBaseParams = listOf(
|
||||
ParsedPermission::getBackgroundPermission,
|
||||
ParsedPermission::getGroup,
|
||||
ParsedPermission::getRequestRes,
|
||||
ParsedPermission::getProtectionLevel,
|
||||
ParsedPermission::isTree,
|
||||
)
|
||||
|
||||
override fun subclassExtraParams() = listOf(
|
||||
getter(ParsedPermission::getKnownCerts, setOf("testCert")),
|
||||
getSetByValue(
|
||||
ParsedPermission::getParsedPermissionGroup,
|
||||
ParsedPermission::setParsedPermissionGroup,
|
||||
ParsedPermissionGroup().apply { name = "test.permission.group" },
|
||||
compare = { first, second -> equalBy(first, second, ParsedPermissionGroup::getName) }
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.parsing.parcelling
|
||||
|
||||
import android.content.pm.parsing.component.ParsedProcess
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
|
||||
@ExperimentalContracts
|
||||
class ParsedProcessTest : ParcelableComponentTest(ParsedProcess::class) {
|
||||
|
||||
override val defaultImpl = ParsedProcess()
|
||||
override val creator = ParsedProcess.CREATOR
|
||||
|
||||
override val excludedMethods = listOf(
|
||||
// Copying method
|
||||
"addStateFrom",
|
||||
)
|
||||
|
||||
override val baseParams = listOf(
|
||||
ParsedProcess::getName,
|
||||
ParsedProcess::getGwpAsanMode,
|
||||
ParsedProcess::getMemtagMode,
|
||||
ParsedProcess::getNativeHeapZeroInitialized,
|
||||
)
|
||||
|
||||
override fun extraParams() = listOf(
|
||||
getter(ParsedProcess::getDeniedPermissions, setOf("testDeniedPermission"))
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.parsing.parcelling
|
||||
|
||||
import android.content.pm.PathPermission
|
||||
import android.content.pm.parsing.component.ParsedProvider
|
||||
import android.os.PatternMatcher
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
|
||||
@ExperimentalContracts
|
||||
class ParsedProviderTest : ParsedMainComponentTest(ParsedProvider::class) {
|
||||
|
||||
override val defaultImpl = ParsedProvider()
|
||||
override val creator = ParsedProvider.CREATOR
|
||||
|
||||
override val mainComponentSubclassBaseParams = listOf(
|
||||
ParsedProvider::getAuthority,
|
||||
ParsedProvider::isSyncable,
|
||||
ParsedProvider::getReadPermission,
|
||||
ParsedProvider::getWritePermission,
|
||||
ParsedProvider::isGrantUriPermissions,
|
||||
ParsedProvider::isForceUriPermissions,
|
||||
ParsedProvider::isMultiProcess,
|
||||
ParsedProvider::getInitOrder,
|
||||
)
|
||||
|
||||
override fun mainComponentSubclassExtraParams() = listOf(
|
||||
getSetByValue(
|
||||
ParsedProvider::getUriPermissionPatterns,
|
||||
ParsedProvider::setUriPermissionPatterns,
|
||||
PatternMatcher("testPattern", PatternMatcher.PATTERN_LITERAL),
|
||||
transformGet = { it?.singleOrNull() },
|
||||
transformSet = { arrayOf(it) },
|
||||
compare = { first, second ->
|
||||
equalBy(
|
||||
first, second,
|
||||
PatternMatcher::getPath,
|
||||
PatternMatcher::getType
|
||||
)
|
||||
}
|
||||
),
|
||||
getSetByValue(
|
||||
ParsedProvider::getPathPermissions,
|
||||
ParsedProvider::setPathPermissions,
|
||||
PathPermission(
|
||||
"testPermissionPattern",
|
||||
PatternMatcher.PATTERN_LITERAL,
|
||||
"test.READ_PERMISSION",
|
||||
"test.WRITE_PERMISSION"
|
||||
),
|
||||
transformGet = { it?.singleOrNull() },
|
||||
transformSet = { arrayOf(it) },
|
||||
compare = { first, second ->
|
||||
equalBy(
|
||||
first, second,
|
||||
PatternMatcher::getPath,
|
||||
PatternMatcher::getType,
|
||||
PathPermission::getReadPermission,
|
||||
PathPermission::getWritePermission,
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.parsing.parcelling
|
||||
|
||||
import android.content.pm.parsing.component.ParsedService
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
|
||||
@ExperimentalContracts
|
||||
class ParsedServiceTest : ParsedMainComponentTest(ParsedService::class) {
|
||||
|
||||
override val defaultImpl = ParsedService()
|
||||
override val creator = ParsedService.CREATOR
|
||||
|
||||
override val mainComponentSubclassBaseParams = listOf(
|
||||
ParsedService::getForegroundServiceType,
|
||||
ParsedService::getPermission,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.parsing.parcelling
|
||||
|
||||
import android.content.pm.parsing.component.ParsedUsesPermission
|
||||
import android.os.Parcelable
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
|
||||
@ExperimentalContracts
|
||||
class ParsedUsesPermissionTest : ParcelableComponentTest(ParsedUsesPermission::class) {
|
||||
|
||||
override val defaultImpl = ParsedUsesPermission("", 0)
|
||||
override val creator = ParsedUsesPermission.CREATOR
|
||||
|
||||
override val baseParams = listOf(
|
||||
ParsedUsesPermission::getName,
|
||||
ParsedUsesPermission::getUsesPermissionFlags
|
||||
)
|
||||
|
||||
override fun initialObject() = ParsedUsesPermission("", 0)
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.parsing.parcelling.java;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class TestSubWithCreator extends TestSuperClass {
|
||||
|
||||
@NonNull
|
||||
public static final Parcelable.Creator<TestSubWithCreator> CREATOR =
|
||||
new Parcelable.Creator<TestSubWithCreator>() {
|
||||
@Override
|
||||
public TestSubWithCreator createFromParcel(Parcel source) {
|
||||
return new TestSubWithCreator(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestSubWithCreator[] newArray(int size) {
|
||||
return new TestSubWithCreator[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Nullable
|
||||
private String subString;
|
||||
|
||||
public TestSubWithCreator() {
|
||||
}
|
||||
|
||||
public TestSubWithCreator(@NonNull Parcel in) {
|
||||
super(in);
|
||||
subString = in.readString();
|
||||
}
|
||||
|
||||
public void writeSubToParcel(@NonNull Parcel parcel, int flags) {
|
||||
super.writeToParcel(parcel, flags);
|
||||
parcel.writeString(subString);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.parsing.parcelling.java;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Parcel;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class TestSubWithoutCreator extends TestSuperClass {
|
||||
|
||||
@Nullable
|
||||
private String subString;
|
||||
|
||||
public TestSubWithoutCreator() {
|
||||
}
|
||||
|
||||
public TestSubWithoutCreator(@NonNull Parcel in) {
|
||||
super(in);
|
||||
subString = in.readString();
|
||||
}
|
||||
|
||||
public void writeSubToParcel(@NonNull Parcel parcel, int flags) {
|
||||
super.writeToParcel(parcel, flags);
|
||||
parcel.writeString(subString);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.parsing.parcelling.java;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.internal.util.DataClass;
|
||||
|
||||
@DataClass(genGetters = true, genSetters = true, genBuilder = false, genAidl = false,
|
||||
genParcelable = true, genConstructor = false)
|
||||
public class TestSuperClass implements Parcelable {
|
||||
|
||||
@Nullable
|
||||
private String superString;
|
||||
|
||||
public TestSuperClass() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Code below generated by codegen v1.0.23.
|
||||
//
|
||||
// DO NOT MODIFY!
|
||||
// CHECKSTYLE:OFF Generated code
|
||||
//
|
||||
// To regenerate run:
|
||||
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSuperClass.java
|
||||
//
|
||||
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
|
||||
// Settings > Editor > Code Style > Formatter Control
|
||||
//@formatter:off
|
||||
|
||||
|
||||
@DataClass.Generated.Member
|
||||
public @Nullable String getSuperString() {
|
||||
return superString;
|
||||
}
|
||||
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull TestSuperClass setSuperString(@NonNull String value) {
|
||||
superString = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
|
||||
// You can override field parcelling by defining methods like:
|
||||
// void parcelFieldName(Parcel dest, int flags) { ... }
|
||||
|
||||
byte flg = 0;
|
||||
if (superString != null) flg |= 0x1;
|
||||
dest.writeByte(flg);
|
||||
if (superString != null) dest.writeString(superString);
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public int describeContents() { return 0; }
|
||||
|
||||
/** @hide */
|
||||
@SuppressWarnings({"unchecked", "RedundantCast"})
|
||||
@DataClass.Generated.Member
|
||||
protected TestSuperClass(@NonNull android.os.Parcel in) {
|
||||
// You can override field unparcelling by defining methods like:
|
||||
// static FieldType unparcelFieldName(Parcel in) { ... }
|
||||
|
||||
byte flg = in.readByte();
|
||||
String _superString = (flg & 0x1) == 0 ? null : in.readString();
|
||||
|
||||
this.superString = _superString;
|
||||
|
||||
// onConstructed(); // You can define this method to get a callback
|
||||
}
|
||||
|
||||
@DataClass.Generated.Member
|
||||
public static final @NonNull Parcelable.Creator<TestSuperClass> CREATOR
|
||||
= new Parcelable.Creator<TestSuperClass>() {
|
||||
@Override
|
||||
public TestSuperClass[] newArray(int size) {
|
||||
return new TestSuperClass[size];
|
||||
}
|
||||
|
||||
@Override
|
||||
public TestSuperClass createFromParcel(@NonNull android.os.Parcel in) {
|
||||
return new TestSuperClass(in);
|
||||
}
|
||||
};
|
||||
|
||||
@DataClass.Generated(
|
||||
time = 1624381019144L,
|
||||
codegenVersion = "1.0.23",
|
||||
sourceFile = "frameworks/base/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/java/TestSuperClass.java",
|
||||
inputSignatures = "private @android.annotation.Nullable java.lang.String superString\nclass TestSuperClass extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genAidl=false, genParcelable=true, genConstructor=false)")
|
||||
@Deprecated
|
||||
private void __metadata() {}
|
||||
|
||||
|
||||
//@formatter:on
|
||||
// End of generated code
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.pm.test.util
|
||||
|
||||
import com.google.common.truth.Expect
|
||||
import org.junit.rules.TestRule
|
||||
import org.junit.runner.Description
|
||||
import org.junit.runners.model.Statement
|
||||
|
||||
/**
|
||||
* Wrapper for [Expect] which supports ignoring any failures. This should be used with caution, but
|
||||
* it allows a base test to be written which doesn't switch success/failure in the test itself,
|
||||
* preventing any logic errors from causing the test to accidentally succeed.
|
||||
*/
|
||||
internal class IgnoreableExpect : TestRule {
|
||||
|
||||
val expect = Expect.create()
|
||||
|
||||
private var ignore = false
|
||||
|
||||
override fun apply(base: Statement?, description: Description?): Statement {
|
||||
return object : Statement() {
|
||||
override fun evaluate() {
|
||||
ignore = false
|
||||
try {
|
||||
expect.apply(base, description).evaluate()
|
||||
} catch (t: Throwable) {
|
||||
if (!ignore) {
|
||||
throw t
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun ignore() {
|
||||
ignore = true
|
||||
}
|
||||
}
|
||||
@@ -949,7 +949,7 @@ public class PackageParserTest {
|
||||
.addConfigPreference(new ConfigurationInfo())
|
||||
.addReqFeature(new FeatureInfo())
|
||||
.addFeatureGroup(new FeatureGroupInfo())
|
||||
.setCompileSdkVersionCodename("foo23")
|
||||
.setCompileSdkVersionCodeName("foo23")
|
||||
.setCompileSdkVersion(100)
|
||||
.setOverlayCategory("foo24")
|
||||
.setOverlayIsStatic(true)
|
||||
|
||||
Reference in New Issue
Block a user