Add tests for the introduced fixes
Add a test for applying kotlin-android plugin with com.android.feature Add a test for Databinding (not passing yet with 3.0.0+, until 3.0.0-alpha4 is released, which contains the fix from the Android side). Add missing test project android-databinding. Refactor and improve the tests * Remove redundant files from test project 'android-databinding' * Refactoring and minor improvements in the tests
This commit is contained in:
+28
-2
@@ -8,13 +8,39 @@ import java.io.File
|
|||||||
|
|
||||||
|
|
||||||
class KotlinAndroidGradleIT : AbstractKotlinAndroidGradleTests(gradleVersion = "3.3", androidGradlePluginVersion = "2.3.0")
|
class KotlinAndroidGradleIT : AbstractKotlinAndroidGradleTests(gradleVersion = "3.3", androidGradlePluginVersion = "2.3.0")
|
||||||
class KotlinAndroid30GradleIT : AbstractKotlinAndroidGradleTests(gradleVersion = "4.0-rc-1", androidGradlePluginVersion = "3.0.0-alpha2")
|
|
||||||
class KotlinAndroidWithJackGradleIT : AbstractKotlinAndroidWithJackGradleTests(gradleVersion = "3.3", androidGradlePluginVersion = "2.3.+")
|
class KotlinAndroidWithJackGradleIT : AbstractKotlinAndroidWithJackGradleTests(gradleVersion = "3.3", androidGradlePluginVersion = "2.3.+")
|
||||||
|
|
||||||
|
class KotlinAndroid30GradleIT : AbstractKotlinAndroidGradleTests(gradleVersion = "4.0-rc-1", androidGradlePluginVersion = "3.0.0-alpha2") {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testApplyWithFeaturePlugin() {
|
||||||
|
val project = Project("AndroidProject", gradleVersion)
|
||||||
|
|
||||||
|
project.setupWorkingDir()
|
||||||
|
File(project.projectDir, "Lib/build.gradle").modify { text ->
|
||||||
|
// Change the applied plugin to com.android.feature
|
||||||
|
text.replace("com.android.library", "com.android.feature").apply { assert(!equals(text)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that Kotlin tasks were created for both lib and feature variants:
|
||||||
|
val kotlinTaskNames =
|
||||||
|
listOf("Debug", "Release").flatMap { buildType ->
|
||||||
|
listOf("Flavor1", "Flavor2").flatMap { flavor ->
|
||||||
|
listOf("", "Feature").map { isFeature -> ":Lib:compile$flavor$buildType${isFeature}Kotlin" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
project.build(":Lib:assemble") {
|
||||||
|
assertSuccessful()
|
||||||
|
assertContains(*kotlinTaskNames.toTypedArray())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const val ANDROID_HOME_PATH = "../../../dependencies/androidSDK"
|
const val ANDROID_HOME_PATH = "../../../dependencies/androidSDK"
|
||||||
|
|
||||||
abstract class AbstractKotlinAndroidGradleTests(
|
abstract class AbstractKotlinAndroidGradleTests(
|
||||||
private val gradleVersion: String,
|
protected val gradleVersion: String,
|
||||||
private val androidGradlePluginVersion: String
|
private val androidGradlePluginVersion: String
|
||||||
) : BaseGradleIT() {
|
) : BaseGradleIT() {
|
||||||
|
|
||||||
|
|||||||
+14
-1
@@ -6,7 +6,7 @@ import java.io.File
|
|||||||
|
|
||||||
class Kapt3Android30IT : Kapt3AndroidIT() {
|
class Kapt3Android30IT : Kapt3AndroidIT() {
|
||||||
override val androidGradlePluginVersion: String
|
override val androidGradlePluginVersion: String
|
||||||
get() = "3.0.0-alpha1"
|
get() = "3.0.0-alpha3"
|
||||||
}
|
}
|
||||||
|
|
||||||
open class Kapt3AndroidIT : Kapt3BaseIT() {
|
open class Kapt3AndroidIT : Kapt3BaseIT() {
|
||||||
@@ -106,4 +106,17 @@ open class Kapt3AndroidIT : Kapt3BaseIT() {
|
|||||||
assertFileExists("build/generated/source/kapt/release/io/realm/DefaultRealmModuleMediator.java")
|
assertFileExists("build/generated/source/kapt/release/io/realm/DefaultRealmModuleMediator.java")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
open fun testDatabinding() {
|
||||||
|
val project = Project("android-databinding", GRADLE_VERSION, directoryPrefix = "kapt2")
|
||||||
|
val options = androidBuildOptions()
|
||||||
|
|
||||||
|
project.build("compileReleaseSources", options = options) {
|
||||||
|
assertSuccessful()
|
||||||
|
assertKaptSuccessful()
|
||||||
|
assertFileExists("app/build/generated/source/kapt/release/com/example/databinding/BR.java")
|
||||||
|
assertFileExists("app/build/generated/source/kapt/release/com/example/databinding/databinding/ActivityTestBinding.java")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+36
@@ -0,0 +1,36 @@
|
|||||||
|
apply plugin: 'com.android.application'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
apply plugin: 'kotlin-kapt'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 24
|
||||||
|
buildToolsVersion "25.0.2"
|
||||||
|
defaultConfig {
|
||||||
|
applicationId "com.example.databinding"
|
||||||
|
minSdkVersion 21
|
||||||
|
targetSdkVersion 24
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
}
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dataBinding {
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
maven { url 'https://maven.google.com' }
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
|
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
|
kapt "com.android.databinding:compiler:$android_tools_version"
|
||||||
|
compile 'com.android.support.constraint:constraint-layout:1.0.2'
|
||||||
|
testCompile 'junit:junit:4.12'
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.example.databinding">
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:supportsRtl="true"
|
||||||
|
android:theme="@style/AppTheme">
|
||||||
|
<activity android:name=".MainActivity">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
+99
@@ -0,0 +1,99 @@
|
|||||||
|
package com.example.databinding
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.databinding.*
|
||||||
|
import android.databinding.adapters.AdapterViewBindingAdapter
|
||||||
|
import android.support.annotation.IntegerRes
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.*
|
||||||
|
import android.widget.*
|
||||||
|
|
||||||
|
|
||||||
|
interface Displayable {
|
||||||
|
fun displayString(res: Resources): String
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@InverseBindingMethods(
|
||||||
|
InverseBindingMethod(type = Spinner::class, attribute = "selectionEnum", method = "getSelectedItem", event = "app:selectionAttrChanged")
|
||||||
|
)
|
||||||
|
open class EnumAdapter<DispEnum>(val context: Context,
|
||||||
|
enumClass: Class<DispEnum>,
|
||||||
|
@IntegerRes var resource: Int = android.R.layout.simple_spinner_item,
|
||||||
|
@IntegerRes var dropDownResource: Int = android.R.layout.simple_spinner_dropdown_item,
|
||||||
|
val isOptional: Boolean = false) :
|
||||||
|
BaseAdapter() where DispEnum : Displayable, DispEnum : Enum<DispEnum>
|
||||||
|
{
|
||||||
|
val inflater: LayoutInflater = LayoutInflater.from(context)
|
||||||
|
val konstants: Array<DispEnum> = enumClass.enumConstants
|
||||||
|
|
||||||
|
override fun getItem(position: Int): DispEnum? {
|
||||||
|
if (isOptional) {
|
||||||
|
return if (position == 0) null else konstants[position - 1]
|
||||||
|
}
|
||||||
|
return konstants[position]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemId(position: Int): Long = position + 0L
|
||||||
|
|
||||||
|
override fun getCount(): Int = konstants.size + if (isOptional) 1 else 0
|
||||||
|
|
||||||
|
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||||
|
return createViewFromResource(position, convertView, parent, resource)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||||
|
return createViewFromResource(position, convertView, parent, dropDownResource)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createViewFromResource(position: Int, convertView: View?, parent: ViewGroup, resource: Int): View {
|
||||||
|
val view = convertView ?: inflater.inflate(resource, parent, false)
|
||||||
|
val textView: TextView
|
||||||
|
try {
|
||||||
|
textView = view as TextView
|
||||||
|
} catch (e: ClassCastException) {
|
||||||
|
Log.e("EnumAdapter", "You must supply a resource ID for a TextView")
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
val enum = getItem(position)
|
||||||
|
textView.text = enum?.displayString(context.resources) ?: "-----"
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic fun optionalPosition(e: Enum<*>?): Int {
|
||||||
|
e?.let { return it.ordinal + 1}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@BindingAdapter("app:selectionEnum", "app:selectionChanged", "app:selectionAttrChanged", requireAll = false)
|
||||||
|
fun bindSpinnerEnum(spinner: Spinner, newValue: Enum<*>?,
|
||||||
|
itemSelectedListener: AdapterViewBindingAdapter.OnItemSelected?,
|
||||||
|
changeListener: InverseBindingListener?) {
|
||||||
|
val spinnerAdapter = spinner.adapter
|
||||||
|
if (spinnerAdapter !is EnumAdapter<*>) {
|
||||||
|
throw UnsupportedOperationException("app:selectionEnum attribute on Spinner requires EnumAdapter")
|
||||||
|
}
|
||||||
|
if (changeListener == null && itemSelectedListener == null)
|
||||||
|
spinner.onItemSelectedListener = null
|
||||||
|
else
|
||||||
|
spinner.onItemSelectedListener = AdapterViewBindingAdapter.OnItemSelectedComponentListener(itemSelectedListener, nothingingSelectedListener, changeListener)
|
||||||
|
|
||||||
|
val isOptional = spinnerAdapter.isOptional
|
||||||
|
if (!isOptional && newValue == null) {
|
||||||
|
throw IllegalStateException("Can't set a null value for app:selectionEnum, adapter.isOptional is false")
|
||||||
|
}
|
||||||
|
if (spinner.selectedItem != newValue) {
|
||||||
|
val sel = if (isOptional) EnumAdapter.optionalPosition(newValue) else newValue!!.ordinal
|
||||||
|
spinner.setSelection(sel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val nothingingSelectedListener = object : AdapterViewBindingAdapter.OnNothingSelected {
|
||||||
|
override fun onNothingSelected(parent: AdapterView<*>?) {
|
||||||
|
}
|
||||||
|
}
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
package com.example.databinding
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.databinding.DataBindingUtil
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.MotionEvent
|
||||||
|
import android.widget.Toast
|
||||||
|
import com.example.databinding.databinding.ActivityTestBinding
|
||||||
|
|
||||||
|
class MainActivity : Activity() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
val binding: ActivityTestBinding = DataBindingUtil.setContentView(this, R.layout.activity_test)
|
||||||
|
val uprof = UserProfile()
|
||||||
|
binding.userProfile = uprof
|
||||||
|
binding.context = this
|
||||||
|
binding.genderPicker.adapter = EnumAdapter(this, Gender::class.java)
|
||||||
|
binding.genderPicker.setOnTouchListener { v, event ->
|
||||||
|
if (event.actionMasked == MotionEvent.ACTION_DOWN)
|
||||||
|
spinnerClicked = true
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var spinnerClicked = false
|
||||||
|
fun spinnerClicked() {
|
||||||
|
spinnerClicked = true
|
||||||
|
}
|
||||||
|
fun selectionChanged() {
|
||||||
|
if (spinnerClicked)
|
||||||
|
Toast.makeText(this, "sdds", Toast.LENGTH_LONG).show()
|
||||||
|
spinnerClicked = false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clickHandler(uprof: UserProfile): Boolean = true
|
||||||
|
|
||||||
|
fun longClickHandler(uprof: UserProfile): Boolean = true
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package com.example.databinding
|
||||||
|
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.databinding.BaseObservable
|
||||||
|
|
||||||
|
class UserProfile : BaseObservable() {
|
||||||
|
open var gender: Gender = Gender.Female
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Gender(val display: String): Displayable {
|
||||||
|
Male("male"), Female("female");
|
||||||
|
override fun displayString(res: Resources): String = display
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<data>
|
||||||
|
<variable name="userProfile" type="com.example.databinding.UserProfile" />
|
||||||
|
<variable name="context" type="com.example.databinding.MainActivity" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent" android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:onClick="@{() -> context.clickHandler(userProfile)}"
|
||||||
|
android:onLongClick="@{() -> context.longClickHandler(userProfile)}"
|
||||||
|
>
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/genderPicker"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:selectionEnum="@={userProfile.gender}"
|
||||||
|
app:selectionChanged="@{(p, v, pos, id) -> context.selectionChanged()}"
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</layout>
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
<resources>
|
||||||
|
<string name="app_name">ActivityRideUpTest</string>
|
||||||
|
</resources>
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
<resources>
|
||||||
|
|
||||||
|
<!-- Base application theme. -->
|
||||||
|
<style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
|
||||||
|
<!-- Customize your theme here. -->
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="EditProfileRow">
|
||||||
|
<item name="android:layout_marginBottom">18dp</item>
|
||||||
|
<item name="android:layout_column">0</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="EditProfileRowColumn" parent="EditProfileRow">
|
||||||
|
<item name="android:layout_marginEnd">5dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</resources>
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
mavenLocal()
|
||||||
|
maven { url 'https://maven.google.com' }
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath "com.android.tools.build:gradle:$android_tools_version"
|
||||||
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
|
||||||
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
// in the individual module build.gradle files
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
mavenLocal()
|
||||||
|
maven { url 'https://maven.google.com' }
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user