Files
agent-framework/python/packages/declarative/tests/test_powerfx_functions.py
T
Evan Mattson 9c094573e8 Python: Add declarative workflow runtime (#2815)
* Further support for declarative python workflows

* Add tests. Clean up for typing and formatting

* Improvements and cleanup

* Typing cleanup. Improve docstrings

* Proper code in docstrings

* Fix malformed code-block directive in docstring

* Remove dead links

* PR feedback

* Address PR feedback

* Address PR feedback

* Remove sl

* Update devui frontend

* More cleanup

* Fix uv lock

* Skip Py 3.14 tests as powerfx doesn't support it

* Fix mypy error

* Fix for tool calls

* Removed stale docstring

* Fix lint

* Standardize on .NET namespaces. Revert DevUI changes (bring in later)

* Implement remaining items for Python declarative support to match dotnet
2026-01-13 07:11:21 +00:00

243 lines
6.9 KiB
Python

# Copyright (c) Microsoft. All rights reserved.
"""Tests for custom PowerFx-like functions."""
from agent_framework_declarative._workflows._powerfx_functions import (
CUSTOM_FUNCTIONS,
assistant_message,
concat_text,
count_rows,
find,
first,
is_blank,
last,
lower,
message_text,
search_table,
system_message,
upper,
user_message,
)
class TestMessageText:
"""Tests for MessageText function."""
def test_message_text_from_string(self):
"""Test extracting text from a plain string."""
assert message_text("Hello") == "Hello"
def test_message_text_from_single_dict(self):
"""Test extracting text from a single message dict."""
msg = {"role": "assistant", "content": "Hello world"}
assert message_text(msg) == "Hello world"
def test_message_text_from_list(self):
"""Test extracting text from a list of messages."""
msgs = [
{"role": "user", "content": "Hi"},
{"role": "assistant", "content": "Hello"},
]
assert message_text(msgs) == "Hi Hello"
def test_message_text_from_none(self):
"""Test that None returns empty string."""
assert message_text(None) == ""
def test_message_text_empty_list(self):
"""Test that empty list returns empty string."""
assert message_text([]) == ""
class TestUserMessage:
"""Tests for UserMessage function."""
def test_user_message_creates_dict(self):
"""Test that UserMessage creates correct dict."""
msg = user_message("Hello")
assert msg == {"role": "user", "content": "Hello"}
def test_user_message_with_none(self):
"""Test UserMessage with None."""
msg = user_message(None)
assert msg == {"role": "user", "content": ""}
class TestAssistantMessage:
"""Tests for AssistantMessage function."""
def test_assistant_message_creates_dict(self):
"""Test that AssistantMessage creates correct dict."""
msg = assistant_message("Hello")
assert msg == {"role": "assistant", "content": "Hello"}
class TestSystemMessage:
"""Tests for SystemMessage function."""
def test_system_message_creates_dict(self):
"""Test that SystemMessage creates correct dict."""
msg = system_message("You are helpful")
assert msg == {"role": "system", "content": "You are helpful"}
class TestIsBlank:
"""Tests for IsBlank function."""
def test_is_blank_none(self):
"""Test that None is blank."""
assert is_blank(None) is True
def test_is_blank_empty_string(self):
"""Test that empty string is blank."""
assert is_blank("") is True
def test_is_blank_whitespace(self):
"""Test that whitespace-only string is blank."""
assert is_blank(" ") is True
def test_is_blank_empty_list(self):
"""Test that empty list is blank."""
assert is_blank([]) is True
def test_is_blank_non_empty(self):
"""Test that non-empty values are not blank."""
assert is_blank("hello") is False
assert is_blank([1, 2, 3]) is False
assert is_blank(0) is False
class TestCountRows:
"""Tests for CountRows function."""
def test_count_rows_list(self):
"""Test counting list items."""
assert count_rows([1, 2, 3]) == 3
def test_count_rows_empty(self):
"""Test counting empty list."""
assert count_rows([]) == 0
def test_count_rows_none(self):
"""Test counting None."""
assert count_rows(None) == 0
class TestFirstLast:
"""Tests for First and Last functions."""
def test_first_returns_first_item(self):
"""Test that First returns first item."""
assert first([1, 2, 3]) == 1
def test_last_returns_last_item(self):
"""Test that Last returns last item."""
assert last([1, 2, 3]) == 3
def test_first_empty_returns_none(self):
"""Test that First returns None for empty list."""
assert first([]) is None
def test_last_empty_returns_none(self):
"""Test that Last returns None for empty list."""
assert last([]) is None
class TestFind:
"""Tests for Find function."""
def test_find_substring(self):
"""Test finding a substring."""
result = find("world", "Hello world")
assert result == 7 # 1-based index
def test_find_not_found(self):
"""Test when substring not found - returns Blank (None) per PowerFx semantics."""
result = find("xyz", "Hello world")
assert result is None
def test_find_at_start(self):
"""Test finding at start of string."""
result = find("Hello", "Hello world")
assert result == 1
class TestUpperLower:
"""Tests for Upper and Lower functions."""
def test_upper(self):
"""Test uppercase conversion."""
assert upper("hello") == "HELLO"
def test_lower(self):
"""Test lowercase conversion."""
assert lower("HELLO") == "hello"
def test_upper_none(self):
"""Test upper with None."""
assert upper(None) == ""
class TestConcatText:
"""Tests for Concat function."""
def test_concat_simple_list(self):
"""Test concatenating simple list."""
assert concat_text(["a", "b", "c"], separator=", ") == "a, b, c"
def test_concat_with_field(self):
"""Test concatenating with field extraction."""
items = [{"name": "Alice"}, {"name": "Bob"}]
assert concat_text(items, field="name", separator=", ") == "Alice, Bob"
class TestSearchTable:
"""Tests for Search function."""
def test_search_finds_matching(self):
"""Test search finds matching items."""
items = [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25},
{"name": "Charlie", "age": 35},
]
result = search_table(items, "Bob", "name")
assert len(result) == 1
assert result[0]["name"] == "Bob"
def test_search_case_insensitive(self):
"""Test search is case insensitive."""
items = [{"name": "Alice"}]
result = search_table(items, "alice", "name")
assert len(result) == 1
def test_search_partial_match(self):
"""Test search finds partial matches."""
items = [{"name": "Alice Smith"}, {"name": "Bob Jones"}]
result = search_table(items, "Smith", "name")
assert len(result) == 1
class TestCustomFunctionsRegistry:
"""Tests for the CUSTOM_FUNCTIONS registry."""
def test_all_functions_registered(self):
"""Test that all functions are in the registry."""
expected = [
"MessageText",
"UserMessage",
"AssistantMessage",
"SystemMessage",
"IsBlank",
"CountRows",
"First",
"Last",
"Find",
"Upper",
"Lower",
"Concat",
"Search",
]
for name in expected:
assert name in CUSTOM_FUNCTIONS