1 /* 2 * Copyright 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.xr.scenecore 18 19 import androidx.xr.runtime.internal.ActivityPose.HitTestFilter as RtHitTestFilter 20 import androidx.xr.runtime.internal.ActivitySpace as RtActivitySpace 21 import androidx.xr.runtime.internal.AnchorPlacement as RtAnchorPlacement 22 import androidx.xr.runtime.internal.Dimensions as RuntimeDimensions 23 import androidx.xr.runtime.internal.Entity as RuntimeEntity 24 import androidx.xr.runtime.internal.HitTestResult as RuntimeHitTestResult 25 import androidx.xr.runtime.internal.InputEvent as RuntimeInputEvent 26 import androidx.xr.runtime.internal.InputEvent.Companion.HitInfo as RuntimeHitInfo 27 import androidx.xr.runtime.internal.JxrPlatformAdapter 28 import androidx.xr.runtime.internal.MoveEvent as RuntimeMoveEvent 29 import androidx.xr.runtime.internal.PixelDimensions as RuntimePixelDimensions 30 import androidx.xr.runtime.internal.PlaneSemantic as RtPlaneSemantic 31 import androidx.xr.runtime.internal.PlaneType as RtPlaneType 32 import androidx.xr.runtime.internal.ResizeEvent as RuntimeResizeEvent 33 import androidx.xr.runtime.internal.SpatialCapabilities as RuntimeSpatialCapabilities 34 import androidx.xr.runtime.internal.SpatialVisibility as RuntimeSpatialVisibility 35 import androidx.xr.runtime.internal.TextureSampler as RuntimeTextureSampler 36 import androidx.xr.runtime.math.Matrix4 37 import androidx.xr.runtime.math.Pose 38 import androidx.xr.runtime.math.Quaternion 39 import androidx.xr.runtime.math.Ray 40 import androidx.xr.runtime.math.Vector3 41 import androidx.xr.scenecore.ActivityPose.HitTestFilter 42 import com.google.common.truth.Truth.assertThat 43 import kotlin.test.assertFailsWith 44 import org.junit.Test 45 import org.mockito.kotlin.mock 46 import org.mockito.kotlin.whenever 47 48 class UtilsTest { 49 @Test verifyDefaultPoseIsIdentitynull50 fun verifyDefaultPoseIsIdentity() { 51 val rtPose = Pose.Identity 52 53 assertThat(rtPose.translation.x).isZero() 54 assertThat(rtPose.translation.y).isZero() 55 assertThat(rtPose.translation.z).isZero() 56 assertThat(rtPose.rotation.x).isZero() 57 assertThat(rtPose.rotation.y).isZero() 58 assertThat(rtPose.rotation.z).isZero() 59 assertThat(rtPose.rotation.w).isEqualTo(1f) 60 } 61 62 @Test verifyPoseToRtPoseConversionnull63 fun verifyPoseToRtPoseConversion() { 64 val rtPose = Pose(Vector3(1f, 2f, 3f), Quaternion(1f, 2f, 3f, 4f).toNormalized()) 65 66 assertThat(rtPose.translation.x).isEqualTo(1f) 67 assertThat(rtPose.translation.y).isEqualTo(2f) 68 assertThat(rtPose.translation.z).isEqualTo(3f) 69 70 // The quaternion is always normalized, so the retrieved values differ from the original 71 // ones. 72 assertThat(rtPose.rotation.x).isWithin(1e-5f).of(0.18257418f) 73 assertThat(rtPose.rotation.y).isWithin(1e-5f).of(0.36514837f) 74 assertThat(rtPose.rotation.z).isWithin(1e-5f).of(0.5477225f) 75 assertThat(rtPose.rotation.w).isWithin(1e-5f).of(0.73029673f) 76 } 77 78 @Test verifyRtPoseToPoseConversionnull79 fun verifyRtPoseToPoseConversion() { 80 val pose = Pose(Vector3(1f, 2f, 3f), Quaternion(1f, 2f, 3f, 4f).toNormalized()) 81 82 assertThat(pose.translation.x).isEqualTo(1f) 83 assertThat(pose.translation.y).isEqualTo(2f) 84 assertThat(pose.translation.z).isEqualTo(3f) 85 86 // The quaternion is always normalized, so the retrieved values differ from the original 87 // ones. 88 assertThat(pose.rotation.x).isWithin(1e-5f).of(0.18257418f) 89 assertThat(pose.rotation.y).isWithin(1e-5f).of(0.36514837f) 90 assertThat(pose.rotation.z).isWithin(1e-5f).of(0.5477225f) 91 assertThat(pose.rotation.w).isWithin(1e-5f).of(0.73029673f) 92 } 93 94 @Test verifyRtVector3toVector3null95 fun verifyRtVector3toVector3() { 96 val vector3: Vector3 = Vector3(1f, 2f, 3f) 97 assertThat(vector3.x).isEqualTo(1f) 98 assertThat(vector3.y).isEqualTo(2f) 99 assertThat(vector3.z).isEqualTo(3f) 100 } 101 102 @Test verifyVector3toRtVector3null103 fun verifyVector3toRtVector3() { 104 val rtVector3: Vector3 = Vector3(1f, 2f, 3f) 105 assertThat(rtVector3.x).isEqualTo(1f) 106 assertThat(rtVector3.y).isEqualTo(2f) 107 assertThat(rtVector3.z).isEqualTo(3f) 108 } 109 110 @Test verifyRtMoveEventToMoveEventnull111 fun verifyRtMoveEventToMoveEvent() { 112 val vector0 = Vector3(0f, 0f, 0f) 113 val vector1 = Vector3(1f, 1f, 1f) 114 val vector2 = Vector3(2f, 2f, 2f) 115 116 val initialInputRay = Ray(vector0, vector1) 117 val currentInputRay = Ray(vector1, vector2) 118 val entityManager = EntityManager() 119 val activitySpace = mock<RtActivitySpace>() 120 entityManager.setEntityForRtEntity(activitySpace, mock<Entity>()) 121 val moveEvent = 122 RuntimeMoveEvent( 123 RuntimeMoveEvent.MOVE_STATE_ONGOING, 124 initialInputRay, 125 currentInputRay, 126 Pose(), 127 Pose(vector1, Quaternion.Identity), 128 vector1, 129 vector1, 130 activitySpace, 131 null, 132 null, 133 ) 134 .toMoveEvent(entityManager) 135 136 assertThat(moveEvent.moveState).isEqualTo(MoveEvent.MOVE_STATE_ONGOING) 137 138 assertThat(moveEvent.initialInputRay.origin.x).isEqualTo(0f) 139 assertThat(moveEvent.initialInputRay.origin.y).isEqualTo(0f) 140 assertThat(moveEvent.initialInputRay.origin.z).isEqualTo(0f) 141 assertThat(moveEvent.initialInputRay.direction.x).isEqualTo(1f) 142 assertThat(moveEvent.initialInputRay.direction.y).isEqualTo(1f) 143 assertThat(moveEvent.initialInputRay.direction.z).isEqualTo(1f) 144 145 assertThat(moveEvent.currentInputRay.origin.x).isEqualTo(1f) 146 assertThat(moveEvent.currentInputRay.origin.y).isEqualTo(1f) 147 assertThat(moveEvent.currentInputRay.origin.z).isEqualTo(1f) 148 assertThat(moveEvent.currentInputRay.direction.x).isEqualTo(2f) 149 assertThat(moveEvent.currentInputRay.direction.y).isEqualTo(2f) 150 assertThat(moveEvent.currentInputRay.direction.z).isEqualTo(2f) 151 152 assertThat(moveEvent.previousPose.translation.x).isEqualTo(0f) 153 assertThat(moveEvent.previousPose.translation.y).isEqualTo(0f) 154 assertThat(moveEvent.previousPose.translation.z).isEqualTo(0f) 155 assertThat(moveEvent.previousPose.rotation.x).isEqualTo(0f) 156 assertThat(moveEvent.previousPose.rotation.y).isEqualTo(0f) 157 assertThat(moveEvent.previousPose.rotation.z).isEqualTo(0f) 158 assertThat(moveEvent.previousPose.rotation.w).isEqualTo(1f) 159 160 assertThat(moveEvent.currentPose.translation.x).isEqualTo(1f) 161 assertThat(moveEvent.currentPose.translation.y).isEqualTo(1f) 162 assertThat(moveEvent.currentPose.translation.z).isEqualTo(1f) 163 assertThat(moveEvent.currentPose.rotation.x).isEqualTo(0f) 164 assertThat(moveEvent.currentPose.rotation.y).isEqualTo(0f) 165 assertThat(moveEvent.currentPose.rotation.z).isEqualTo(0f) 166 assertThat(moveEvent.currentPose.rotation.w).isEqualTo(1f) 167 168 assertThat(moveEvent.previousScale).isEqualTo(1f) 169 170 assertThat(moveEvent.currentScale).isEqualTo(1f) 171 } 172 173 @Test verifyRtInputEventToInputEventConversionnull174 fun verifyRtInputEventToInputEventConversion() { 175 val entityManager = EntityManager() 176 val activitySpace = mock<RtActivitySpace>() 177 entityManager.setEntityForRtEntity(activitySpace, mock<Entity>()) 178 val inputEvent = 179 RuntimeInputEvent( 180 RuntimeInputEvent.SOURCE_HANDS, 181 RuntimeInputEvent.POINTER_TYPE_LEFT, 182 123456789, 183 Vector3(1f, 2f, 3f), 184 Vector3(4f, 5f, 6f), 185 RuntimeInputEvent.ACTION_DOWN, 186 null, 187 null, 188 ) 189 .toInputEvent(entityManager) 190 assertThat(inputEvent.source).isEqualTo(InputEvent.SOURCE_HANDS) 191 assertThat(inputEvent.pointerType).isEqualTo(InputEvent.POINTER_TYPE_LEFT) 192 assertThat(inputEvent.timestamp).isEqualTo(123456789) 193 assertThat(inputEvent.origin.x).isEqualTo(1f) 194 assertThat(inputEvent.origin.y).isEqualTo(2f) 195 assertThat(inputEvent.origin.z).isEqualTo(3f) 196 assertThat(inputEvent.direction.x).isEqualTo(4f) 197 assertThat(inputEvent.direction.y).isEqualTo(5f) 198 assertThat(inputEvent.direction.z).isEqualTo(6f) 199 assertThat(inputEvent.action).isEqualTo(InputEvent.ACTION_DOWN) 200 } 201 202 @Test verifyRtHitInfoToHitInfoConversionnull203 fun verifyRtHitInfoToHitInfoConversion() { 204 val entityManager = EntityManager() 205 val rtMockEntity = mock<RuntimeEntity>() 206 val mockEntity = mock<Entity>() 207 entityManager.setEntityForRtEntity(rtMockEntity, mockEntity) 208 val hitPosition = Vector3(1f, 2f, 3f) 209 val transform = Matrix4.Identity 210 val hitInfo = RuntimeHitInfo(rtMockEntity, hitPosition, transform).toHitInfo(entityManager) 211 212 assertThat(hitInfo).isNotNull() 213 assertThat(hitInfo!!.inputEntity).isEqualTo(mockEntity) 214 assertThat(hitInfo.hitPosition).isEqualTo(hitPosition) 215 assertThat(hitInfo.transform).isEqualTo(transform) 216 } 217 218 @Test verifyRtHitInfoToHitInfoConversionWhenEntityNotFoundnull219 fun verifyRtHitInfoToHitInfoConversionWhenEntityNotFound() { 220 val entityManager = EntityManager() 221 val rtMockEntity = mock<RuntimeEntity>() 222 val hitPosition = Vector3(1f, 2f, 3f) 223 val transform = Matrix4.Identity 224 val hitInfo = RuntimeHitInfo(rtMockEntity, hitPosition, transform).toHitInfo(entityManager) 225 226 // EntityManager does not have the entity for the given RuntimeEntity, so the hit info is 227 // null. 228 assertThat(hitInfo).isNull() 229 } 230 231 @Test verifyRtDimensionsToDimensionsnull232 fun verifyRtDimensionsToDimensions() { 233 val dimensions: Dimensions = RuntimeDimensions(2f, 4f, 6f).toDimensions() 234 assertThat(dimensions.width).isEqualTo(2f) 235 assertThat(dimensions.height).isEqualTo(4f) 236 assertThat(dimensions.depth).isEqualTo(6f) 237 } 238 239 @Test verifyRtPixelDimensionsToPixelDimensionsnull240 fun verifyRtPixelDimensionsToPixelDimensions() { 241 val pixelDimensions: PixelDimensions = RuntimePixelDimensions(14, 15).toPixelDimensions() 242 assertThat(pixelDimensions.width).isEqualTo(14) 243 assertThat(pixelDimensions.height).isEqualTo(15) 244 } 245 246 @Test verifyPixelDimensionsToRtPixelDimensionsnull247 fun verifyPixelDimensionsToRtPixelDimensions() { 248 val pixelDimensions: PixelDimensions = RuntimePixelDimensions(17, 18).toPixelDimensions() 249 assertThat(pixelDimensions.width).isEqualTo(17) 250 assertThat(pixelDimensions.height).isEqualTo(18) 251 } 252 253 @Test verifyRuntimeResizeEventToResizeEventnull254 fun verifyRuntimeResizeEventToResizeEvent() { 255 val resizeEvent: ResizeEvent = 256 RuntimeResizeEvent(RuntimeResizeEvent.RESIZE_STATE_START, RuntimeDimensions(1f, 3f, 5f)) 257 .toResizeEvent() 258 assertThat(resizeEvent.resizeState).isEqualTo(ResizeEvent.RESIZE_STATE_START) 259 assertThat(resizeEvent.newSize.width).isEqualTo(1f) 260 assertThat(resizeEvent.newSize.height).isEqualTo(3f) 261 assertThat(resizeEvent.newSize.depth).isEqualTo(5f) 262 } 263 264 @Test runtimeSpatialCapabilitiesToSpatialCapabilities_noCapabilitiesnull265 fun runtimeSpatialCapabilitiesToSpatialCapabilities_noCapabilities() { 266 val caps = RuntimeSpatialCapabilities(0).toSpatialCapabilities() 267 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_UI)).isFalse() 268 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_3D_CONTENT)).isFalse() 269 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_PASSTHROUGH_CONTROL)) 270 .isFalse() 271 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_APP_ENVIRONMENT)) 272 .isFalse() 273 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO)) 274 .isFalse() 275 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_EMBED_ACTIVITY)) 276 .isFalse() 277 } 278 279 @Test runtimeSpatialCapabilitiesToSpatialCapabilities_singleCapabilitynull280 fun runtimeSpatialCapabilitiesToSpatialCapabilities_singleCapability() { 281 var caps = 282 RuntimeSpatialCapabilities(RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_UI) 283 .toSpatialCapabilities() 284 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_UI)).isTrue() 285 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_3D_CONTENT)).isFalse() 286 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_PASSTHROUGH_CONTROL)) 287 .isFalse() 288 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_APP_ENVIRONMENT)) 289 .isFalse() 290 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO)) 291 .isFalse() 292 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_EMBED_ACTIVITY)) 293 .isFalse() 294 295 caps = 296 RuntimeSpatialCapabilities(RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO) 297 .toSpatialCapabilities() 298 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_UI)).isFalse() 299 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_3D_CONTENT)).isFalse() 300 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_PASSTHROUGH_CONTROL)) 301 .isFalse() 302 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_APP_ENVIRONMENT)) 303 .isFalse() 304 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO)) 305 .isTrue() 306 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_EMBED_ACTIVITY)) 307 .isFalse() 308 } 309 310 @Test runtimeSpatialCapabilitiesToSpatialCapabilities_allCapabilitiesnull311 fun runtimeSpatialCapabilitiesToSpatialCapabilities_allCapabilities() { 312 val caps = 313 RuntimeSpatialCapabilities( 314 RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_UI or 315 RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_3D_CONTENT or 316 RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_PASSTHROUGH_CONTROL or 317 RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_APP_ENVIRONMENT or 318 RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO or 319 RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_EMBED_ACTIVITY 320 ) 321 .toSpatialCapabilities() 322 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_UI)).isTrue() 323 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_3D_CONTENT)).isTrue() 324 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_PASSTHROUGH_CONTROL)) 325 .isTrue() 326 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_APP_ENVIRONMENT)) 327 .isTrue() 328 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO)) 329 .isTrue() 330 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_EMBED_ACTIVITY)) 331 .isTrue() 332 } 333 334 @Test runtimeSpatialCapabilitiesToSpatialCapabilities_mixedCapabilitiesnull335 fun runtimeSpatialCapabilitiesToSpatialCapabilities_mixedCapabilities() { 336 var caps = 337 RuntimeSpatialCapabilities( 338 RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_3D_CONTENT or 339 RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO 340 ) 341 .toSpatialCapabilities() 342 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_UI)).isFalse() 343 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_3D_CONTENT)).isTrue() 344 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_PASSTHROUGH_CONTROL)) 345 .isFalse() 346 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_APP_ENVIRONMENT)) 347 .isFalse() 348 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO)) 349 .isTrue() 350 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_EMBED_ACTIVITY)) 351 .isFalse() 352 353 caps = 354 RuntimeSpatialCapabilities( 355 RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_UI or 356 RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_PASSTHROUGH_CONTROL or 357 RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_APP_ENVIRONMENT or 358 RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_EMBED_ACTIVITY 359 ) 360 .toSpatialCapabilities() 361 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_UI)).isTrue() 362 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_3D_CONTENT)).isFalse() 363 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_PASSTHROUGH_CONTROL)) 364 .isTrue() 365 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_APP_ENVIRONMENT)) 366 .isTrue() 367 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO)) 368 .isFalse() 369 assertThat(caps.hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_EMBED_ACTIVITY)) 370 .isTrue() 371 } 372 373 @Test RtSpatialVisibilityToSpatialVisibility_convertsCorrectlynull374 fun RtSpatialVisibilityToSpatialVisibility_convertsCorrectly() { 375 assertThat( 376 listOf( 377 RuntimeSpatialVisibility(RuntimeSpatialVisibility.UNKNOWN), 378 RuntimeSpatialVisibility(RuntimeSpatialVisibility.OUTSIDE_FOV), 379 RuntimeSpatialVisibility(RuntimeSpatialVisibility.PARTIALLY_WITHIN_FOV), 380 RuntimeSpatialVisibility(RuntimeSpatialVisibility.WITHIN_FOV), 381 ) 382 .map { it.toSpatialVisibility() } 383 ) 384 .containsExactly( 385 SpatialVisibility(SpatialVisibility.UNKNOWN), 386 SpatialVisibility(SpatialVisibility.OUTSIDE_FOV), 387 SpatialVisibility(SpatialVisibility.PARTIALLY_WITHIN_FOV), 388 SpatialVisibility(SpatialVisibility.WITHIN_FOV), 389 ) 390 .inOrder() 391 } 392 393 @Test intToSpatialVisibility_convertsCorrectlynull394 fun intToSpatialVisibility_convertsCorrectly() { 395 assertThat( 396 listOf( 397 RuntimeSpatialVisibility.UNKNOWN, 398 RuntimeSpatialVisibility.OUTSIDE_FOV, 399 RuntimeSpatialVisibility.PARTIALLY_WITHIN_FOV, 400 RuntimeSpatialVisibility.WITHIN_FOV, 401 ) 402 .map { it.toSpatialVisibilityValue() } 403 ) 404 .containsExactly( 405 SpatialVisibility.UNKNOWN, 406 SpatialVisibility.OUTSIDE_FOV, 407 SpatialVisibility.PARTIALLY_WITHIN_FOV, 408 SpatialVisibility.WITHIN_FOV, 409 ) 410 .inOrder() 411 } 412 413 @Test intToSpatialVisibility_invalidValue_throwsErrornull414 fun intToSpatialVisibility_invalidValue_throwsError() { 415 assertFailsWith<IllegalStateException> { 100.toSpatialVisibilityValue() } 416 } 417 418 @Test intToMoveState_convertsCorrectlynull419 fun intToMoveState_convertsCorrectly() { 420 assertThat( 421 listOf( 422 RuntimeMoveEvent.MOVE_STATE_START, 423 RuntimeMoveEvent.MOVE_STATE_ONGOING, 424 RuntimeMoveEvent.MOVE_STATE_END, 425 ) 426 .map { it.toMoveState() } 427 ) 428 .containsExactly( 429 MoveEvent.MOVE_STATE_START, 430 MoveEvent.MOVE_STATE_ONGOING, 431 MoveEvent.MOVE_STATE_END, 432 ) 433 .inOrder() 434 } 435 436 @Test intToMoveState_invalidValue_throwsErrornull437 fun intToMoveState_invalidValue_throwsError() { 438 assertFailsWith<IllegalStateException> { 100.toMoveState() } 439 } 440 441 @Test intToResizeState_convertsCorrectlynull442 fun intToResizeState_convertsCorrectly() { 443 assertThat( 444 listOf( 445 RuntimeResizeEvent.RESIZE_STATE_UNKNOWN, 446 RuntimeResizeEvent.RESIZE_STATE_START, 447 RuntimeResizeEvent.RESIZE_STATE_ONGOING, 448 RuntimeResizeEvent.RESIZE_STATE_END, 449 ) 450 .map { it.toResizeState() } 451 ) 452 .containsExactly( 453 ResizeEvent.RESIZE_STATE_UNKNOWN, 454 ResizeEvent.RESIZE_STATE_START, 455 ResizeEvent.RESIZE_STATE_ONGOING, 456 ResizeEvent.RESIZE_STATE_END, 457 ) 458 .inOrder() 459 } 460 461 @Test intToResizeState_invalidValue_throwsErrornull462 fun intToResizeState_invalidValue_throwsError() { 463 assertFailsWith<IllegalStateException> { 100.toResizeState() } 464 } 465 466 @Test intToInputEventSource_convertsCorrectlynull467 fun intToInputEventSource_convertsCorrectly() { 468 assertThat( 469 listOf( 470 RuntimeInputEvent.SOURCE_UNKNOWN, 471 RuntimeInputEvent.SOURCE_HEAD, 472 RuntimeInputEvent.SOURCE_CONTROLLER, 473 RuntimeInputEvent.SOURCE_HANDS, 474 RuntimeInputEvent.SOURCE_MOUSE, 475 RuntimeInputEvent.SOURCE_GAZE_AND_GESTURE, 476 ) 477 .map { it.toInputEventSource() } 478 ) 479 .containsExactly( 480 InputEvent.SOURCE_UNKNOWN, 481 InputEvent.SOURCE_HEAD, 482 InputEvent.SOURCE_CONTROLLER, 483 InputEvent.SOURCE_HANDS, 484 InputEvent.SOURCE_MOUSE, 485 InputEvent.SOURCE_GAZE_AND_GESTURE, 486 ) 487 .inOrder() 488 } 489 490 @Test intToInputEventSource_invalidValue_throwsErrornull491 fun intToInputEventSource_invalidValue_throwsError() { 492 assertFailsWith<IllegalStateException> { 100.toInputEventSource() } 493 } 494 495 @Test intToInputEventPointerType_convertsCorrectlynull496 fun intToInputEventPointerType_convertsCorrectly() { 497 assertThat( 498 listOf( 499 RuntimeInputEvent.POINTER_TYPE_DEFAULT, 500 RuntimeInputEvent.POINTER_TYPE_LEFT, 501 RuntimeInputEvent.POINTER_TYPE_RIGHT, 502 ) 503 .map { it.toInputEventPointerType() } 504 ) 505 .containsExactly( 506 InputEvent.POINTER_TYPE_DEFAULT, 507 InputEvent.POINTER_TYPE_LEFT, 508 InputEvent.POINTER_TYPE_RIGHT, 509 ) 510 .inOrder() 511 } 512 513 @Test intToInputEventPointerType_invalidValue_throwsErrornull514 fun intToInputEventPointerType_invalidValue_throwsError() { 515 assertFailsWith<IllegalStateException> { 100.toInputEventPointerType() } 516 } 517 518 @Test intToSpatialCapability_convertsCorrectlynull519 fun intToSpatialCapability_convertsCorrectly() { 520 assertThat( 521 listOf( 522 RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_UI, 523 RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_3D_CONTENT, 524 RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_PASSTHROUGH_CONTROL, 525 RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_APP_ENVIRONMENT, 526 RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO, 527 RuntimeSpatialCapabilities.SPATIAL_CAPABILITY_EMBED_ACTIVITY, 528 ) 529 .map { it.toSpatialCapability() } 530 ) 531 .containsExactly( 532 SpatialCapabilities.SPATIAL_CAPABILITY_UI, 533 SpatialCapabilities.SPATIAL_CAPABILITY_3D_CONTENT, 534 SpatialCapabilities.SPATIAL_CAPABILITY_PASSTHROUGH_CONTROL, 535 SpatialCapabilities.SPATIAL_CAPABILITY_APP_ENVIRONMENT, 536 SpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO, 537 SpatialCapabilities.SPATIAL_CAPABILITY_EMBED_ACTIVITY, 538 ) 539 .inOrder() 540 } 541 542 @Test intToInputEventAction_convertsCorrectlynull543 fun intToInputEventAction_convertsCorrectly() { 544 assertThat( 545 listOf( 546 RuntimeInputEvent.ACTION_DOWN, 547 RuntimeInputEvent.ACTION_UP, 548 RuntimeInputEvent.ACTION_MOVE, 549 RuntimeInputEvent.ACTION_CANCEL, 550 RuntimeInputEvent.ACTION_HOVER_MOVE, 551 RuntimeInputEvent.ACTION_HOVER_ENTER, 552 RuntimeInputEvent.ACTION_HOVER_EXIT, 553 ) 554 .map { it.toInputEventAction() } 555 ) 556 .containsExactly( 557 InputEvent.ACTION_DOWN, 558 InputEvent.ACTION_UP, 559 InputEvent.ACTION_MOVE, 560 InputEvent.ACTION_CANCEL, 561 InputEvent.ACTION_HOVER_MOVE, 562 InputEvent.ACTION_HOVER_ENTER, 563 InputEvent.ACTION_HOVER_EXIT, 564 ) 565 .inOrder() 566 } 567 568 @Test intToInputEventAction_invalidValue_throwsErrornull569 fun intToInputEventAction_invalidValue_throwsError() { 570 assertFailsWith<IllegalStateException> { 100.toInputEventAction() } 571 } 572 573 @Test anchorPlacementToRuntimeAnchorPlacement_setsCorrectlynull574 fun anchorPlacementToRuntimeAnchorPlacement_setsCorrectly() { 575 val mockRuntime = mock<JxrPlatformAdapter>() 576 val mockAnchorPlacement1 = mock<RtAnchorPlacement>() 577 val mockAnchorPlacement2 = mock<RtAnchorPlacement>() 578 whenever( 579 mockRuntime.createAnchorPlacementForPlanes( 580 setOf(RtPlaneType.HORIZONTAL), 581 setOf(RtPlaneSemantic.ANY), 582 ) 583 ) 584 .thenReturn(mockAnchorPlacement1) 585 whenever( 586 mockRuntime.createAnchorPlacementForPlanes( 587 setOf(RtPlaneType.ANY), 588 setOf(RtPlaneSemantic.WALL, RtPlaneSemantic.FLOOR), 589 ) 590 ) 591 .thenReturn(mockAnchorPlacement2) 592 593 val anchorPlacement1 = 594 AnchorPlacement.createForPlanes(planeTypeFilter = setOf(PlaneType.HORIZONTAL)) 595 val anchorPlacement2 = 596 AnchorPlacement.createForPlanes( 597 planeSemanticFilter = setOf(PlaneSemantic.WALL, PlaneSemantic.FLOOR) 598 ) 599 600 val rtPlacementSet = 601 setOf(anchorPlacement1, anchorPlacement2).toRtAnchorPlacement(mockRuntime) 602 603 assertThat(rtPlacementSet.size).isEqualTo(2) 604 assertThat(rtPlacementSet).containsExactly(mockAnchorPlacement1, mockAnchorPlacement2) 605 } 606 607 @Test anchorPlacementToRuntimeAnchotPlacementEmptySet_returnsEmptySetnull608 fun anchorPlacementToRuntimeAnchotPlacementEmptySet_returnsEmptySet() { 609 val mockRuntime = mock<JxrPlatformAdapter>() 610 611 val rtPlacementSet = emptySet<AnchorPlacement>().toRtAnchorPlacement(mockRuntime) 612 613 assertThat(rtPlacementSet).isEmpty() 614 } 615 616 @Test intToTextureSampler_convertsCorrectlynull617 fun intToTextureSampler_convertsCorrectly() { 618 val sampler: TextureSampler = 619 TextureSampler( 620 TextureSampler.MinFilter.NEAREST, 621 TextureSampler.MagFilter.LINEAR, 622 TextureSampler.WrapMode.CLAMP_TO_EDGE, 623 TextureSampler.WrapMode.REPEAT, 624 TextureSampler.WrapMode.MIRRORED_REPEAT, 625 TextureSampler.CompareMode.NONE, 626 TextureSampler.CompareFunc.LE, 627 2, 628 ) 629 630 val rtSampler: RuntimeTextureSampler = sampler.toRtTextureSampler() 631 632 assertThat(rtSampler.wrapModeS).isEqualTo(RuntimeTextureSampler.CLAMP_TO_EDGE) 633 assertThat(rtSampler.wrapModeT).isEqualTo(RuntimeTextureSampler.REPEAT) 634 assertThat(rtSampler.wrapModeR).isEqualTo(RuntimeTextureSampler.MIRRORED_REPEAT) 635 assertThat(rtSampler.minFilter).isEqualTo(RuntimeTextureSampler.NEAREST) 636 assertThat(rtSampler.magFilter).isEqualTo(RuntimeTextureSampler.MAG_LINEAR) 637 assertThat(rtSampler.compareMode).isEqualTo(RuntimeTextureSampler.NONE) 638 assertThat(rtSampler.compareFunc).isEqualTo(RuntimeTextureSampler.LE) 639 assertThat(rtSampler.anisotropyLog2).isEqualTo(2) 640 } 641 642 @Test runtimeHitTestResultToHitTestResult_convertsCorrectlynull643 fun runtimeHitTestResultToHitTestResult_convertsCorrectly() { 644 val hitPosition = Vector3(1f, 2f, 3f) 645 val surfaceNormal = Vector3(4f, 5f, 6f) 646 val surfaceType = RuntimeHitTestResult.HitTestSurfaceType.HIT_TEST_RESULT_SURFACE_TYPE_PLANE 647 val distance = 7f 648 val rtHitTestResult = 649 RuntimeHitTestResult(hitPosition, surfaceNormal, surfaceType, distance) 650 val hitTestResult = rtHitTestResult.toHitTestResult() 651 assertThat(hitTestResult.hitPosition).isEqualTo(hitPosition) 652 assertThat(hitTestResult.surfaceNormal).isEqualTo(surfaceNormal) 653 assertThat(hitTestResult.surfaceType).isEqualTo(HitTestResult.SurfaceType.PLANE) 654 assertThat(hitTestResult.distance).isEqualTo(distance) 655 } 656 657 @Test runtimeHitTestResultWithNullToHitTestResult_convertsCorrectlynull658 fun runtimeHitTestResultWithNullToHitTestResult_convertsCorrectly() { 659 val hitPosition = null 660 val surfaceNormal = null 661 val surfaceType = 662 RuntimeHitTestResult.HitTestSurfaceType.HIT_TEST_RESULT_SURFACE_TYPE_UNKNOWN 663 val distance = Float.POSITIVE_INFINITY 664 val rtHitTestResult = 665 RuntimeHitTestResult(hitPosition, surfaceNormal, surfaceType, distance) 666 667 val hitTestResult = rtHitTestResult.toHitTestResult() 668 669 assertThat(hitTestResult.hitPosition).isEqualTo(hitPosition) 670 assertThat(hitTestResult.surfaceNormal).isEqualTo(surfaceNormal) 671 assertThat(hitTestResult.surfaceType).isEqualTo(HitTestResult.SurfaceType.UNKNOWN) 672 assertThat(hitTestResult.distance).isEqualTo(distance) 673 } 674 675 @Test hitTestFilterToRuntimeHitTestFilter_convertsCorrectlynull676 fun hitTestFilterToRuntimeHitTestFilter_convertsCorrectly() { 677 assertThat( 678 listOf( 679 0, 680 HitTestFilter.SELF_SCENE, 681 HitTestFilter.OTHER_SCENES, 682 (HitTestFilter.SELF_SCENE or HitTestFilter.OTHER_SCENES), 683 ) 684 .map { it.toRtHitTestFilter() } 685 ) 686 .containsExactly( 687 0, 688 RtHitTestFilter.SELF_SCENE, 689 RtHitTestFilter.OTHER_SCENES, 690 RtHitTestFilter.SELF_SCENE or RtHitTestFilter.OTHER_SCENES, 691 ) 692 } 693 694 @Test runtimeHitTestSurfaceTypeToHitTestSurfaceType_convertsCorrectlynull695 fun runtimeHitTestSurfaceTypeToHitTestSurfaceType_convertsCorrectly() { 696 assertThat( 697 listOf( 698 RuntimeHitTestResult.HitTestSurfaceType 699 .HIT_TEST_RESULT_SURFACE_TYPE_UNKNOWN, 700 RuntimeHitTestResult.HitTestSurfaceType.HIT_TEST_RESULT_SURFACE_TYPE_PLANE, 701 RuntimeHitTestResult.HitTestSurfaceType.HIT_TEST_RESULT_SURFACE_TYPE_OBJECT, 702 ) 703 .map { it.toHitTestSurfaceType() } 704 ) 705 .containsExactly( 706 HitTestResult.SurfaceType.UNKNOWN, 707 HitTestResult.SurfaceType.PLANE, 708 HitTestResult.SurfaceType.OBJECT, 709 ) 710 } 711 } 712