def test_descriptor_to_xml(self) -> None:
        """Test descriptor to XML."""
        descriptor = didl_lite.Descriptor(id="1",
                                          name_space="ns",
                                          type="type",
                                          text="Text")
        item = didl_lite.AudioItem(
            id="0",
            parent_id="0",
            title="Audio Item Title",
            restricted="1",
            language="English",
            descriptors=[descriptor],
        )
        didl_string = didl_lite.to_xml_string(item).decode("utf-8")
        didl_el = ET.fromstring(didl_string)

        item_el = didl_el.find("./didl_lite:item", NAMESPACES)
        assert item_el is not None

        descriptor_el = item_el.find("./didl_lite:desc", NAMESPACES)
        assert descriptor_el is not None
        assert len(descriptor_el.attrib) == 3
        assert descriptor_el.attrib["id"] == "1"
        assert descriptor_el.attrib["nameSpace"] == "ns"
        assert descriptor_el.attrib["type"] == "type"
        assert descriptor_el.text == "Text"

        descriptor = didl_lite.Descriptor(id="2", name_space="ns2")
        descriptor_el = descriptor.to_xml()
        assert descriptor_el is not None
        assert len(descriptor_el.attrib) == 2
        assert descriptor_el.attrib["id"] == "2"
        assert descriptor_el.attrib["nameSpace"] == "ns2"
async def test_browse_media_search(
    device_source_mock: DmsDeviceSource, dms_device_mock: Mock
) -> None:
    """Test async_browse_media with a search query."""
    query = 'dc:title contains "FooBar"'
    object_details = (("111", "FooBar baz"), ("432", "Not FooBar"), ("99", "FooBar"))
    dms_device_mock.async_search_directory.return_value = DmsDevice.BrowseResult(
        [
            didl_lite.DidlObject(id=ob_id, restricted="false", title=title)
            for ob_id, title in object_details
        ],
        3,
        3,
        0,
    )
    # Test that descriptors are skipped
    dms_device_mock.async_search_directory.return_value.result.insert(
        1, didl_lite.Descriptor("id", "name_space")
    )

    result = await device_source_mock.async_browse_media(f"?{query}")
    assert result.identifier == f"{MOCK_SOURCE_ID}/?{query}"
    assert result.title == "Search results"
    assert result.children

    for obj, child in zip(object_details, result.children):
        assert isinstance(child, BrowseMediaSource)
        assert child.identifier == f"{MOCK_SOURCE_ID}/:{obj[0]}"
        assert child.title == obj[1]
        assert not child.children
async def test_resolve_media_search(
    device_source_mock: DmsDeviceSource, dms_device_mock: Mock
) -> None:
    """Test the async_resolve_search method via async_resolve_media."""
    res_url: Final = "foo/bar"
    res_abs_url: Final = f"{MOCK_DEVICE_BASE_URL}/{res_url}"
    res_mime: Final = "audio/mpeg"

    # No results
    dms_device_mock.async_search_directory.return_value = DmsDevice.BrowseResult(
        [], 0, 0, 0
    )
    with pytest.raises(Unresolvable, match='Nothing found for dc:title="thing"'):
        await device_source_mock.async_resolve_media('?dc:title="thing"')
    assert dms_device_mock.async_search_directory.await_args_list == [
        call(
            container_id="0",
            search_criteria='dc:title="thing"',
            metadata_filter="*",
            requested_count=1,
        )
    ]

    # One result
    dms_device_mock.async_search_directory.reset_mock()
    didl_item = didl_lite.Item(
        id="thing's id",
        restricted="false",
        title="thing",
        res=[didl_lite.Resource(uri=res_url, protocol_info=f"http-get:*:{res_mime}:")],
    )
    dms_device_mock.async_search_directory.return_value = DmsDevice.BrowseResult(
        [didl_item], 1, 1, 0
    )
    result = await device_source_mock.async_resolve_media('?dc:title="thing"')
    assert result.url == res_abs_url
    assert result.mime_type == res_mime
    assert result.didl_metadata is didl_item
    assert dms_device_mock.async_search_directory.await_count == 1
    # Values should be taken from search result, not querying the item's metadata
    assert dms_device_mock.async_browse_metadata.await_count == 0

    # Two results - uses the first
    dms_device_mock.async_search_directory.return_value = DmsDevice.BrowseResult(
        [didl_item], 1, 2, 0
    )
    result = await device_source_mock.async_resolve_media('?dc:title="thing"')
    assert result.url == res_abs_url
    assert result.mime_type == res_mime
    assert result.didl_metadata is didl_item

    # Bad result
    dms_device_mock.async_search_directory.return_value = DmsDevice.BrowseResult(
        [didl_lite.Descriptor("id", "namespace")], 1, 1, 0
    )
    with pytest.raises(Unresolvable, match="Descriptor.* is not a DidlObject"):
        await device_source_mock.async_resolve_media('?dc:title="thing"')