Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,9 @@ class FlutterPlugin : Plugin<Project> {
}

private fun addTaskForLockfileGeneration(rootProject: Project) {
if (rootProject.tasks.findByName("generateLockfiles") != null) {
return
}
rootProject.tasks.register("generateLockfiles") {
doLast {
rootProject.subprojects.forEach { subproject ->
Expand Down
108 changes: 105 additions & 3 deletions packages/flutter_tools/gradle/src/test/kotlin/FlutterPluginTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,113 @@ class FlutterPluginTest {
// mock method calls that are invoked by the args to NativePluginLoaderReflectionBridge
every { project.extraProperties } returns mockk()
every { project.file(flutterExtension.source!!) } returns mockk()
val mockTaskContainer = mockk<TaskContainer>(relaxed = true)
every { project.tasks } returns mockTaskContainer
every { mockTaskContainer.findByName("generateLockfiles") } returns null
val flutterPlugin = FlutterPlugin()
flutterPlugin.apply(project)

verify { project.tasks.register("generateLockfiles", any()) }
verify { project.tasks.register("javaVersion", any()) }
verify { project.tasks.register("printBuildVariants", any()) }
verify { mockTaskContainer.register("generateLockfiles", any()) }
verify { mockTaskContainer.register("javaVersion", any()) }
verify { mockTaskContainer.register("printBuildVariants", any()) }
}

@Test
fun `FlutterPlugin apply() does not register generateLockfiles task if already exists`(
@TempDir tempDir: Path
) {
val projectDir = tempDir.resolve("project-dir").resolve("android").resolve("app")
projectDir.toFile().mkdirs()
val settingsFile = projectDir.parent.resolve("settings.gradle")
settingsFile.writeText("empty for now")
val fakeFlutterSdkDir = tempDir.resolve("fake-flutter-sdk")
fakeFlutterSdkDir.toFile().mkdirs()
val fakeCacheDir = fakeFlutterSdkDir.resolve("bin").resolve("cache")
fakeCacheDir.toFile().mkdirs()
val fakeEngineStampFile = fakeCacheDir.resolve("engine.stamp")
fakeEngineStampFile.writeText(FAKE_ENGINE_STAMP)
val fakeEngineRealmFile = fakeCacheDir.resolve("engine.realm")
fakeEngineRealmFile.writeText(FAKE_ENGINE_REALM)
val project = mockk<Project>(relaxed = true)
val mockAbstractAppExtension =
mockk<AbstractAppExtension>(
moreInterfaces = arrayOf(ApplicationExtension::class),
relaxed = true
)
val mockLibraryExtension = mockk<LibraryExtension>(relaxed = true)
every { project.extensions.findByType(AbstractAppExtension::class.java) } returns mockAbstractAppExtension
val mockAndroidComponentsExtension = mockk<AndroidComponentsExtension<*, *, *>>(relaxed = true)
every { project.extensions.getByType(AndroidComponentsExtension::class.java) } returns mockAndroidComponentsExtension
every { mockAndroidComponentsExtension.selector() } returns
mockk {
every { all() } returns mockk()
}
every { project.extensions.getByType(AbstractAppExtension::class.java) } returns mockAbstractAppExtension
every { project.extensions.getByType(LibraryExtension::class.java) } returns mockLibraryExtension
every { project.extensions.findByName("android") } returns mockAbstractAppExtension
every { project.projectDir } returns projectDir.toFile()
every { project.findProperty("flutter.sdk") } returns fakeFlutterSdkDir.toString()
every { project.file(fakeFlutterSdkDir.toString()) } returns fakeFlutterSdkDir.toFile()
val flutterExtension = FlutterExtension()
every { project.extensions.create("flutter", any<Class<*>>()) } returns flutterExtension
every { project.extensions.findByType(FlutterExtension::class.java) } returns flutterExtension
val mockBaseExtension = mockk<BaseExtension>(relaxed = true)
val mockCommonExtension = mockk<CommonExtension<*, *, *, *, *, *>>(relaxed = true)
val mockDebugBuildType = mockk<com.android.build.api.dsl.ApplicationBuildType>(relaxed = true)
val mockReleaseBuildType = mockk<com.android.build.api.dsl.ApplicationBuildType>(relaxed = true)

// Cast our multi-interface mock instead of creating a brand new one
val mockApplicationExtension = mockAbstractAppExtension as ApplicationExtension

// Mock buildTypes on our new dual-purpose mock so AgpCommonExtensionWrapper can read them
every { mockApplicationExtension.buildTypes.getByName("debug") } returns mockDebugBuildType
every { mockApplicationExtension.buildTypes.getByName("release") } returns mockReleaseBuildType

// Keep the CommonExtension mocks just in case other parts of the plugin look for it
every { mockCommonExtension.buildTypes.getByName("debug") } returns mockDebugBuildType
every { mockCommonExtension.buildTypes.getByName("release") } returns mockReleaseBuildType

every { project.extensions.findByType(BaseExtension::class.java) } returns mockBaseExtension
every { project.extensions.findByType(CommonExtension::class.java) } returns mockCommonExtension

// Pass the dual-purpose mock for any ApplicationExtension lookups
every { project.extensions.findByType(ApplicationExtension::class.java) } returns mockApplicationExtension
every { project.extensions.getByType(ApplicationExtension::class.java) } returns mockApplicationExtension

val mockApplicationDefaultConfig =
mockk<com.android.build.gradle.internal.dsl.DefaultConfig>(
moreInterfaces = arrayOf(ApplicationDefaultConfig::class),
relaxed = true
)
every { mockApplicationExtension.defaultConfig } returns mockApplicationDefaultConfig
every { project.rootProject } returns project
every { project.state.failure as Throwable? } returns null
val mockDirectory = mockk<Directory>(relaxed = true)
every { project.layout.buildDirectory.get() } returns mockDirectory
val mockAndroidSourceSet = mockk<com.android.build.gradle.api.AndroidSourceSet>(relaxed = true)
val mockAndroidSourceDirectorySet = mockk<AndroidSourceDirectorySet>(relaxed = true)
every { mockAndroidSourceSet.jniLibs.srcDir(any()) } returns mockAndroidSourceDirectorySet
every { mockAbstractAppExtension.sourceSets.getByName("main") } returns mockAndroidSourceSet
// mock return of NativePluginLoaderReflectionBridge.getPlugins
mockkObject(NativePluginLoaderReflectionBridge)
every { NativePluginLoaderReflectionBridge.getPlugins(any(), any()) } returns
listOf()
// mock method calls that are invoked by the args to NativePluginLoaderReflectionBridge
every { project.extraProperties } returns mockk()
every { project.file(flutterExtension.source!!) } returns mockk()

// MOCK generateLockfiles task ALREADY EXISTS:
val mockTask = mockk<Task>(relaxed = true)
val mockTaskContainer = mockk<TaskContainer>(relaxed = true)
every { project.tasks } returns mockTaskContainer
every { mockTaskContainer.findByName("generateLockfiles") } returns mockTask

val flutterPlugin = FlutterPlugin()
flutterPlugin.apply(project)

verify(exactly = 0) { mockTaskContainer.register("generateLockfiles", any()) }
verify { mockTaskContainer.register("javaVersion", any()) }
verify { mockTaskContainer.register("printBuildVariants", any()) }
}

@Test
Expand Down Expand Up @@ -208,6 +309,7 @@ class FlutterPluginTest {
// Set up the task container and our task capture
val taskContainer = mockk<TaskContainer>(relaxed = true)
every { project.tasks } returns taskContainer
every { taskContainer.findByName("generateLockfiles") } returns null
val copyTaskActionCaptor = slot<Action<Copy>>()
val copyTask = mockk<Copy>(relaxed = true)
val mockVariant = mockk<com.android.build.gradle.api.ApplicationVariant>(relaxed = true)
Expand Down
Loading