fun canQueryParametersForComposables()

in layout-inspector/testSrc/com/android/tools/idea/layoutinspector/pipeline/appinspection/AppInspectionPropertiesProviderTest.kt [433:625]


  fun canQueryParametersForComposables() {
    inspectorClientSettings.inLiveMode =
      true // Enable live mode, so we only fetch properties on demand

    val modelUpdatedLatch =
      ReportingCountDownLatch(2) // We'll get two tree layout events on start fetch
    inspectorRule.inspectorModel.addModificationListener { _, _, _ ->
      modelUpdatedLatch.countDown()
    }

    inspectorRule.processNotifier.fireConnected(MODERN_PROCESS)
    modelUpdatedLatch.await(TIMEOUT, TIMEOUT_UNIT)

    val provider = inspectorRule.inspectorClient.provider
    val resultQueue = ArrayBlockingQueue<ProviderResult>(1)
    provider.addResultListener { _, view, table ->
      resultQueue.add(
        ProviderResult(view, table, inspectorRule.inspectorModel, inspectorRule.parametersCache)
      )
    }

    inspectorRule.inspectorModel[-2]!!.let { targetNode ->
      provider.requestProperties(targetNode).get()
      val result = resultQueue.poll(TIMEOUT, TIMEOUT_UNIT)!!
      assertThat(result.view).isSameAs(targetNode)
      result.table.run {
        assertParameter("text", PropertyType.STRING, "placeholder")
        assertParameter("clickable", PropertyType.BOOLEAN, "true")
        assertParameter("count", PropertyType.INT32, "7", PropertySection.RECOMPOSITIONS)
        assertParameter("skips", PropertyType.INT32, "14", PropertySection.RECOMPOSITIONS)
      }
    }

    inspectorRule.inspectorModel[-3]!!.let { targetNode ->
      provider.requestProperties(targetNode).get()
      val result = resultQueue.poll(TIMEOUT, TIMEOUT_UNIT)!!
      assertThat(result.view).isSameAs(targetNode)
      result.table.run {
        assertParameter("maxLines", PropertyType.INT32, "16")
        assertParameter("color", PropertyType.COLOR, "#3700B3")
      }
    }

    inspectorRule.inspectorModel[-4]!!.let { targetNode ->
      provider.requestProperties(targetNode).get()
      val result = resultQueue.poll(TIMEOUT, TIMEOUT_UNIT)!!
      assertThat(result.view).isSameAs(targetNode)
      result.table.run {
        PropertiesSettings.dimensionUnits = DimensionUnits.PIXELS
        assertParameter("elevation", PropertyType.DIMENSION_DP, "1.5px")
        assertParameter("fontSize", PropertyType.DIMENSION_SP, "36.0px")
        assertParameter("textSize", PropertyType.DIMENSION_EM, "2.0em")
      }
      result.table.run {
        PropertiesSettings.dimensionUnits = DimensionUnits.DP
        assertParameter("elevation", PropertyType.DIMENSION_DP, "1.0dp")
        assertParameter("fontSize", PropertyType.DIMENSION_SP, "16.0sp")
        assertParameter("textSize", PropertyType.DIMENSION_EM, "2.0em")
      }
    }

    val parameter =
      inspectorRule.inspectorModel[-5]!!.let { targetNode ->
        provider.requestProperties(targetNode).get()
        val result = resultQueue.poll(TIMEOUT, TIMEOUT_UNIT)!!
        assertThat(result.view).isSameAs(targetNode)

        result.table.run {
          assertParameter("onTextLayout", PropertyType.LAMBDA, "λ")
          assertParameter("dataObject", PropertyType.STRING, "PojoClass")
          val groupItem = this[PARAM_NS, "dataObject"] as ParameterGroupItem
          assertParameter(
            groupItem.children[0],
            "stringProperty",
            PropertyType.STRING,
            "stringValue",
          )
          assertParameter(groupItem.children[1], "intProperty", PropertyType.INT32, "812")
          assertParameter(groupItem.children[2], "lines", PropertyType.STRING, "MyLineClass")
          assertThat(groupItem.children.size).isEqualTo(3)

          groupItem
        }
      }

    // The 1st element of parameter is a reference to parameter itself.
    // When the 1st sub element is expanded in the UI the child elements should be copied from
    // parameter.
    val propertyExpandedLatch = ReportingCountDownLatch(1)
    propertyExpandedLatch.runInEdt {
      val first = parameter.children.first() as ParameterGroupItem
      assertThat(first.children).isEmpty()
      first.expandWhenPossible { restructured ->
        assertThat(restructured).isTrue()
        assertParameter(first.children[0], "stringProperty", PropertyType.STRING, "stringValue")
        assertParameter(first.children[1], "intProperty", PropertyType.INT32, "812")
        assertParameter(first.children[2], "lines", PropertyType.STRING, "MyLineClass")
        assertThat(first.children.size).isEqualTo(3)
        propertyExpandedLatch.countDown()
      }
    }
    propertyExpandedLatch.await(TIMEOUT, TIMEOUT_UNIT)

    // The last element of parameter is a reference to a value that has not been loaded from the
    // agent yet.
    // When the last element is expanded in the UI the child elements will be loaded from the agent.
    val propertyDownloadedLatch = ReportingCountDownLatch(1)
    val last = parameter.children.last() as ParameterGroupItem
    propertyDownloadedLatch.runInEdt {
      assertThat(last.children).isEmpty()
      last.expandWhenPossible { restructured ->
        assertThat(restructured).isTrue()
        assertParameter(last.children[0], "firstLine", PropertyType.STRING, "Hello World")
        assertParameter(last.children[1], "lastLine", PropertyType.STRING, "End of Text")
        assertParameter(last.children[2], "list", PropertyType.ITERABLE, "List[12]")
        assertThat(last.children.size).isEqualTo(3)
        val list = last.children.last() as ParameterGroupItem
        assertParameter(list.children[0], "[0]", PropertyType.STRING, "a")
        assertParameter(list.children[1], "[3]", PropertyType.STRING, "b")
        assertThat(list.children[2]).isInstanceOf(ShowMoreElementsItem::class.java)
        assertThat(list.children[2].index).isEqualTo(4)
        assertThat(list.children.size).isEqualTo(3)
        propertyDownloadedLatch.countDown()
      }
    }
    propertyDownloadedLatch.await(TIMEOUT, TIMEOUT_UNIT)

    // The list parameter from the expanded parameter is a List of String where only a part of the
    // elements
    // have been downloaded. Download some more elements (first time).
    val moreListElements1 = ReportingCountDownLatch(1)
    val table1 = spy(PTable.create(mock()))
    val event1: AnActionEvent = mock()
    doAnswer {
        val modification = it.getArgument<PTableGroupModification>(1)
        assertThat(modification.added).hasSize(2)
        assertThat(modification.removed).isEmpty()
        moreListElements1.countDown()
      }
      .whenever(table1)
      .updateGroupItems(any(), any())
    doAnswer { table1.component }
      .whenever(event1)
      .getData(Mockito.eq(PlatformCoreDataKeys.CONTEXT_COMPONENT))
    val list = last.children.last() as ParameterGroupItem
    moreListElements1.runInEdt {
      val showMoreItem = list.children[2] as ShowMoreElementsItem
      // Click the "Show more" link:
      showMoreItem.link.actionPerformed(event1)
    }
    moreListElements1.await(TIMEOUT, TIMEOUT_UNIT)
    assertParameter(list, "list", PropertyType.ITERABLE, "List[12]")
    assertThat(list.reference).isNotNull()
    assertParameter(list.children[0], "[0]", PropertyType.STRING, "a")
    assertParameter(list.children[1], "[3]", PropertyType.STRING, "b")
    assertParameter(list.children[2], "[4]", PropertyType.STRING, "c")
    assertParameter(list.children[3], "[6]", PropertyType.STRING, "d")
    assertThat(list.children[4]).isInstanceOf(ShowMoreElementsItem::class.java)
    assertThat(list.children[4].index).isEqualTo(7)
    assertThat(list.children.size).isEqualTo(5)

    // Expand the list a second time:
    val moreListElements2 = ReportingCountDownLatch(1)
    val table2 = spy(PTable.create(mock()))
    val event2: AnActionEvent = mock()
    doAnswer {
        val modification = it.getArgument<PTableGroupModification>(1)
        assertThat(modification.added).hasSize(3)
        assertThat(modification.removed).hasSize(1)
        moreListElements2.countDown()
      }
      .whenever(table2)
      .updateGroupItems(any(), any())
    doAnswer { table2.component }
      .whenever(event2)
      .getData(Mockito.eq(PlatformCoreDataKeys.CONTEXT_COMPONENT))
    moreListElements2.runInEdt {
      val showMoreItem = list.children[4] as ShowMoreElementsItem
      // Click the "Show more" link:
      showMoreItem.link.actionPerformed(event2)
    }
    moreListElements2.await(TIMEOUT, TIMEOUT_UNIT)
    assertParameter(list, "list", PropertyType.ITERABLE, "List[12]")
    assertThat(list.reference).isNull()
    assertParameter(list.children[0], "[0]", PropertyType.STRING, "a")
    assertParameter(list.children[1], "[3]", PropertyType.STRING, "b")
    assertParameter(list.children[2], "[4]", PropertyType.STRING, "c")
    assertParameter(list.children[3], "[6]", PropertyType.STRING, "d")
    assertParameter(list.children[4], "[7]", PropertyType.STRING, "e")
    assertParameter(list.children[5], "[10]", PropertyType.STRING, "f")
    assertParameter(list.children[6], "[11]", PropertyType.STRING, "g")
    assertThat(list.children.size).isEqualTo(7)
  }