commonMain.androidx.compose.ui.test.SemanticsMatcher.kt Maven / Gradle / Ivy
/*
* Copyright 2020 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 androidx.compose.ui.test
import androidx.compose.ui.semantics.SemanticsNode
import androidx.compose.ui.semantics.SemanticsPropertyKey
/**
* Wrapper for semantics matcher lambdas that allows to build string explaining to the developer
* what conditions were being tested.
*/
class SemanticsMatcher(
val description: String,
private val matcher: (SemanticsNode) -> Boolean
) {
companion object {
/**
* Builds a predicate that tests whether the value of the given [key] is equal to
* [expectedValue].
*/
fun expectValue(key: SemanticsPropertyKey, expectedValue: T): SemanticsMatcher {
return SemanticsMatcher("${key.name} = '$expectedValue'") {
it.config.getOrElseNullable(key) { null } == expectedValue
}
}
/**
* Builds a predicate that tests whether the given [key] is defined in semantics.
*/
fun keyIsDefined(key: SemanticsPropertyKey): SemanticsMatcher {
return SemanticsMatcher("${key.name} is defined") {
key in it.config
}
}
/**
* Builds a predicate that tests whether the given [key] is NOT defined in semantics.
*/
fun keyNotDefined(key: SemanticsPropertyKey): SemanticsMatcher {
return SemanticsMatcher("${key.name} is NOT defined") {
key !in it.config
}
}
}
/**
* Returns whether the given node is matched by this matcher.
*/
fun matches(node: SemanticsNode): Boolean {
return matcher(node)
}
/**
* Returns whether at least one of the given nodes is matched by this matcher.
*/
fun matchesAny(nodes: Iterable): Boolean {
return nodes.any(matcher)
}
infix fun and(other: SemanticsMatcher): SemanticsMatcher {
return SemanticsMatcher("($description) && (${other.description})") {
matcher(it) && other.matches(it)
}
}
infix fun or(other: SemanticsMatcher): SemanticsMatcher {
return SemanticsMatcher("($description) || (${other.description})") {
matcher(it) || other.matches(it)
}
}
operator fun not(): SemanticsMatcher {
return SemanticsMatcher("NOT ($description)") {
!matcher(it)
}
}
}