Skip to content

Commit

Permalink
RUMM-2806 Drop the covered wireframes only if top ones have a background
Browse files Browse the repository at this point in the history
  • Loading branch information
mariusc83 committed Dec 16, 2022
1 parent 05aa709 commit b3f7083
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ internal class WireframeUtils {
return false
}
topWireframes.forEach {
if (it.bounds().isCovering(wireframeBounds)) {
if (it.bounds().isCovering(wireframeBounds) && it.isOpaque()) {
return false
}
}
Expand All @@ -72,6 +72,23 @@ internal class WireframeUtils {
}
}

private fun MobileSegment.Wireframe.isOpaque(): Boolean {
return this.shapeStyle()?.isOpaque() ?: false
}

private fun MobileSegment.Wireframe.shapeStyle(): MobileSegment.ShapeStyle? {
return when (this) {
is MobileSegment.Wireframe.TextWireframe -> this.shapeStyle
is MobileSegment.Wireframe.ShapeWireframe -> this.shapeStyle
}
}

private fun MobileSegment.ShapeStyle.isOpaque(): Boolean {
return this.opacity == FULL_OPACITY_ALPHA &&
this.backgroundColor != null &&
this.backgroundColor.takeLast(2) == FULL_OPACITY_ALPHA_AS_HEXA_STRING
}

private fun MobileSegment.Wireframe.ShapeWireframe.bounds(): Bounds {
return Bounds(
left = x + (clip?.left ?: 0),
Expand Down Expand Up @@ -102,4 +119,9 @@ internal class WireframeUtils {
val width: Long,
val height: Long
)

companion object {
const val FULL_OPACITY_ALPHA_AS_HEXA_STRING = "FF"
const val FULL_OPACITY_ALPHA = 1f
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.junit.jupiter.MockitoSettings
import org.mockito.quality.Strictness
import kotlin.math.abs
import kotlin.math.max

@Extensions(
ExtendWith(MockitoExtension::class),
Expand Down Expand Up @@ -239,7 +240,7 @@ internal class WireframeUtilsTest {

@ParameterizedTest
@MethodSource("coverAllWireframes")
fun `M return false W checkIsValidWireframe(){ covered by another }`(
fun `M return false W checkIsValidWireframe(){ covered by another with solid background }`(
fakeWireframe: MobileSegment.Wireframe,
forge: Forge
) {
Expand All @@ -255,7 +256,8 @@ internal class WireframeUtilsTest {
x = fakeX,
y = fakeY,
width = fakeWidth,
height = fakeHeight
height = fakeHeight,
shapeStyle = forge.forgeNonTransparentShapeStyle()
)
fakeCoverAllWireframe
}
Expand All @@ -264,6 +266,121 @@ internal class WireframeUtilsTest {
assertThat(testedWireframeUtils.checkIsValidWireframe(fakeWireframe, topWireframes)).isFalse
}

@ParameterizedTest
@MethodSource("coverAllWireframes")
fun `M return true W checkIsValidWireframe(){ covered by another without background }`(
fakeWireframe: MobileSegment.Wireframe,
forge: Forge
) {
// Given
val topWireframes = forge.aList {
val fakeX = forge.aLong(min = -100, max = fakeWireframe.x())
val fakeY = forge.aLong(min = -100, max = fakeWireframe.y())
val fakeMinWidth = abs(fakeX) - abs(fakeWireframe.x()) + fakeWireframe.width()
val fakeMinHeight = abs(fakeY) - abs(fakeWireframe.y()) + fakeWireframe.height()
val fakeWidth = forge.aLong(min = fakeMinWidth, max = Int.MAX_VALUE.toLong())
val fakeHeight = forge.aLong(min = fakeMinHeight, max = Int.MAX_VALUE.toLong())
val fakeCoverAllWireframe = fakeWireframe.copy(
x = fakeX,
y = fakeY,
width = fakeWidth,
height = fakeHeight,
shapeStyle = null
)
fakeCoverAllWireframe
}

// Then
assertThat(testedWireframeUtils.checkIsValidWireframe(fakeWireframe, topWireframes)).isTrue
}

@ParameterizedTest
@MethodSource("coverAllWireframes")
fun `M return true W checkIsValidWireframe(){ covered by another with translucent background }`(
fakeWireframe: MobileSegment.Wireframe,
forge: Forge
) {
// Given
val topWireframes = forge.aList {
val fakeX = forge.aLong(min = -100, max = fakeWireframe.x())
val fakeY = forge.aLong(min = -100, max = fakeWireframe.y())
val fakeMinWidth = abs(fakeX) - abs(fakeWireframe.x()) + fakeWireframe.width()
val fakeMinHeight = abs(fakeY) - abs(fakeWireframe.y()) + fakeWireframe.height()
val fakeWidth = forge.aLong(min = fakeMinWidth, max = Int.MAX_VALUE.toLong())
val fakeHeight = forge.aLong(min = fakeMinHeight, max = Int.MAX_VALUE.toLong())
val fakeCoverAllWireframe = fakeWireframe.copy(
x = fakeX,
y = fakeY,
width = fakeWidth,
height = fakeHeight,
shapeStyle = forge.forgeNonTransparentShapeStyle()
.copy(opacity = forge.aFloat(min = 0f, max = 1f))
)
fakeCoverAllWireframe
}

// Then
assertThat(testedWireframeUtils.checkIsValidWireframe(fakeWireframe, topWireframes)).isTrue
}

@ParameterizedTest
@MethodSource("coverAllWireframes")
fun `M return true W checkIsValidWireframe(){covered by another with background with no color}`(
fakeWireframe: MobileSegment.Wireframe,
forge: Forge
) {
// Given
val topWireframes = forge.aList {
val fakeX = forge.aLong(min = -100, max = fakeWireframe.x())
val fakeY = forge.aLong(min = -100, max = fakeWireframe.y())
val fakeMinWidth = abs(fakeX) - abs(fakeWireframe.x()) + fakeWireframe.width()
val fakeMinHeight = abs(fakeY) - abs(fakeWireframe.y()) + fakeWireframe.height()
val fakeWidth = forge.aLong(min = fakeMinWidth, max = Int.MAX_VALUE.toLong())
val fakeHeight = forge.aLong(min = fakeMinHeight, max = Int.MAX_VALUE.toLong())
val fakeCoverAllWireframe = fakeWireframe.copy(
x = fakeX,
y = fakeY,
width = fakeWidth,
height = fakeHeight,
shapeStyle = forge.forgeNonTransparentShapeStyle()
.copy(backgroundColor = null)
)
fakeCoverAllWireframe
}

// Then
assertThat(testedWireframeUtils.checkIsValidWireframe(fakeWireframe, topWireframes)).isTrue
}

@ParameterizedTest
@MethodSource("coverAllWireframes")
fun `M return true W checkIsValidWireframe(){covered by another with translucent color}`(
fakeWireframe: MobileSegment.Wireframe,
forge: Forge
) {
// Given
val topWireframes = forge.aList {
val fakeX = forge.aLong(min = -100, max = fakeWireframe.x())
val fakeY = forge.aLong(min = -100, max = fakeWireframe.y())
val fakeMinWidth = abs(fakeX) - abs(fakeWireframe.x()) + fakeWireframe.width()
val fakeMinHeight = abs(fakeY) - abs(fakeWireframe.y()) + fakeWireframe.height()
val fakeWidth = forge.aLong(min = fakeMinWidth, max = Int.MAX_VALUE.toLong())
val fakeHeight = forge.aLong(min = fakeMinHeight, max = Int.MAX_VALUE.toLong())
val fakeCoverAllWireframe = fakeWireframe.copy(
x = fakeX,
y = fakeY,
width = fakeWidth,
height = fakeHeight,
shapeStyle = forge.forgeNonTransparentShapeStyle()
.copy(backgroundColor = forge.aStringMatching("#[0-9A-F]{6}[0-9A-E]{2}"))
)
fakeCoverAllWireframe
}

// Then
assertThat(testedWireframeUtils.checkIsValidWireframe(fakeWireframe, topWireframes)).isTrue
}

@ParameterizedTest
@MethodSource("coverAllWireframes")
fun `M return true W checkIsValidWireframe(){ top is bigger }`(
Expand All @@ -277,7 +394,9 @@ internal class WireframeUtilsTest {
x = fakeWireframe.x(),
y = fakeY,
width = fakeWireframe.width(),
height = fakeWireframe.height()
height = fakeWireframe.height(),
shapeStyle = forge.forgeNonTransparentShapeStyle()

)
fakeCoverAllWireframe
}
Expand All @@ -299,7 +418,8 @@ internal class WireframeUtilsTest {
x = fakeWireframe.x(),
y = fakeWireframe.y(),
width = fakeWireframe.width(),
height = fakeHeight
height = fakeHeight,
shapeStyle = forge.forgeNonTransparentShapeStyle()
)
fakeCoverAllWireframe
}
Expand All @@ -321,7 +441,8 @@ internal class WireframeUtilsTest {
x = fakeX,
y = fakeWireframe.y(),
width = fakeWireframe.width(),
height = fakeWireframe.height()
height = fakeWireframe.height(),
shapeStyle = forge.forgeNonTransparentShapeStyle()
)
fakeCoverAllWireframe
}
Expand All @@ -343,7 +464,8 @@ internal class WireframeUtilsTest {
x = fakeWireframe.x(),
y = fakeWireframe.y(),
width = fakeWidth,
height = fakeWireframe.height()
height = fakeWireframe.height(),
shapeStyle = forge.forgeNonTransparentShapeStyle()
)
fakeCoverAllWireframe
}
Expand Down Expand Up @@ -596,6 +718,13 @@ internal class WireframeUtilsTest {
}
}

private fun MobileSegment.Wireframe.shapeStyle(): MobileSegment.ShapeStyle? {
return when (this) {
is MobileSegment.Wireframe.ShapeWireframe -> shapeStyle
is MobileSegment.Wireframe.TextWireframe -> shapeStyle
}
}

private fun Forge.getForgeryWithIntRangeCoordinates(): MobileSegment.Wireframe {
return getForgery<MobileSegment.Wireframe.ShapeWireframe>()
.copy(
Expand All @@ -605,6 +734,17 @@ internal class WireframeUtilsTest {
height = aLong(min = 1, max = 100)
)
}

private fun Forge.forgeNonTransparentShapeStyle(): MobileSegment.ShapeStyle {
return MobileSegment.ShapeStyle(
backgroundColor = aNullable {
aStringMatching("#[0-9A-F]{6}FF")
},
opacity = 1f,
cornerRadius = aPositiveLong()
)
}

// endregion

companion object {
Expand Down Expand Up @@ -636,20 +776,28 @@ internal class WireframeUtilsTest {
}
}

private fun MobileSegment.Wireframe.copy(x: Long, y: Long, width: Long, height: Long):
private fun MobileSegment.Wireframe.copy(
x: Long,
y: Long,
width: Long,
height: Long,
shapeStyle: MobileSegment.ShapeStyle?
):
MobileSegment.Wireframe {
return when (this) {
is MobileSegment.Wireframe.ShapeWireframe -> copy(
x = x,
y = y,
width = width,
height = height
height = height,
shapeStyle = shapeStyle
)
is MobileSegment.Wireframe.TextWireframe -> copy(
x = x,
y = y,
width = width,
height = height
height = height,
shapeStyle = shapeStyle
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@ internal class ForgeConfigurator : BaseConfigurator() {
forge.addFactory(EnrichedRecordForgeryFactory())
forge.addFactory(WireframeClipForgeryFactory())
forge.addFactory(PointerInteractionDataForgeryFactory())
forge.addFactory(ShapeStyleForgeryFactory())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.android.sessionreplay.utils

import com.datadog.android.sessionreplay.model.MobileSegment
import fr.xgouchet.elmyr.Forge
import fr.xgouchet.elmyr.ForgeryFactory

internal class ShapeStyleForgeryFactory :
ForgeryFactory<MobileSegment.ShapeStyle> {
override fun getForgery(forge: Forge): MobileSegment.ShapeStyle {
return MobileSegment.ShapeStyle(
backgroundColor = forge.aNullable {
forge.aStringMatching("#[0-9A-F]{6}FF")
},
opacity = forge.aFloat(min = 0f, max = 1f),
cornerRadius = forge.aPositiveLong()
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,7 @@ internal class ShapeWireframeForgeryFactory :
y = forge.aPositiveLong(),
width = forge.aPositiveLong(strict = true),
height = forge.aPositiveLong(strict = true),
shapeStyle = forge.aNullable {
MobileSegment.ShapeStyle(
backgroundColor = forge.aNullable {
forge.aStringMatching("#[0-9A-F]{6}FF")
},
opacity = forge.aFloat(min = 0f, max = 1f),
cornerRadius = forge.aPositiveLong()
)
},
shapeStyle = forge.aNullable { getForgery() },
border = forge.aNullable {
MobileSegment.ShapeBorder(
forge.aStringMatching("#[0-9A-F]{6}FF"),
Expand Down

0 comments on commit b3f7083

Please sign in to comment.