feat: +unit test

fixbug: func has no value
This commit is contained in:
莘权 马 2023-12-29 14:52:21 +08:00
parent 5510df5f96
commit 6f039d004d
28 changed files with 367 additions and 552 deletions

View file

@ -1,189 +0,0 @@
# -*- coding: utf-8 -*-
# @Date : 2023/7/22 02:40
# @Author : stellahong (stellahong@deepwisdom.ai)
#
from tests.metagpt.roles.ui_role import UIDesign
llm_resp = """
# UI Design Description
```The user interface for the snake game will be designed in a way that is simple, clean, and intuitive. The main elements of the game such as the game grid, snake, food, score, and game over message will be clearly defined and easy to understand. The game grid will be centered on the screen with the score displayed at the top. The game controls will be intuitive and easy to use. The design will be modern and minimalist with a pleasing color scheme.```
## Selected Elements
Game Grid: The game grid will be a rectangular area in the center of the screen where the game will take place. It will be defined by a border and will have a darker background color.
Snake: The snake will be represented by a series of connected blocks that move across the grid. The color of the snake will be different from the background color to make it stand out.
Food: The food will be represented by small objects that are a different color from the snake and the background. The food will be randomly placed on the grid.
Score: The score will be displayed at the top of the screen. The score will increase each time the snake eats a piece of food.
Game Over: When the game is over, a message will be displayed in the center of the screen. The player will be given the option to restart the game.
## HTML Layout
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Snake Game</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="score">Score: 0</div>
<div class="game-grid">
<!-- Snake and food will be dynamically generated here using JavaScript -->
</div>
<div class="game-over">Game Over</div>
</body>
</html>
```
## CSS Styles (styles.css)
```css
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f0f0f0;
}
.score {
font-size: 2em;
margin-bottom: 1em;
}
.game-grid {
width: 400px;
height: 400px;
display: grid;
grid-template-columns: repeat(20, 1fr);
grid-template-rows: repeat(20, 1fr);
gap: 1px;
background-color: #222;
border: 1px solid #555;
}
.snake-segment {
background-color: #00cc66;
}
.food {
background-color: #cc3300;
}
.control-panel {
display: flex;
justify-content: space-around;
width: 400px;
margin-top: 1em;
}
.control-button {
padding: 1em;
font-size: 1em;
border: none;
background-color: #555;
color: #fff;
cursor: pointer;
}
.game-over {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 3em;
"""
def test_ui_design_parse_css():
ui_design_work = UIDesign(name="UI design action")
css = """
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f0f0f0;
}
.score {
font-size: 2em;
margin-bottom: 1em;
}
.game-grid {
width: 400px;
height: 400px;
display: grid;
grid-template-columns: repeat(20, 1fr);
grid-template-rows: repeat(20, 1fr);
gap: 1px;
background-color: #222;
border: 1px solid #555;
}
.snake-segment {
background-color: #00cc66;
}
.food {
background-color: #cc3300;
}
.control-panel {
display: flex;
justify-content: space-around;
width: 400px;
margin-top: 1em;
}
.control-button {
padding: 1em;
font-size: 1em;
border: none;
background-color: #555;
color: #fff;
cursor: pointer;
}
.game-over {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 3em;
"""
assert ui_design_work.parse_css_code(context=llm_resp) == css
def test_ui_design_parse_html():
ui_design_work = UIDesign(name="UI design action")
html = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Snake Game</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="score">Score: 0</div>
<div class="game-grid">
<!-- Snake and food will be dynamically generated here using JavaScript -->
</div>
<div class="game-over">Game Over</div>
</body>
</html>
"""
assert ui_design_work.parse_css_code(context=llm_resp) == html

View file

@ -7,30 +7,20 @@
@Desc : Unit tests.
"""
import asyncio
from pydantic import BaseModel
import pytest
from metagpt.config import CONFIG
from metagpt.learn.text_to_embedding import text_to_embedding
async def mock_text_to_embedding():
class Input(BaseModel):
input: str
@pytest.mark.asyncio
async def test_text_to_embedding():
# Prerequisites
assert CONFIG.OPENAI_API_KEY
inputs = [{"input": "Panda emoji"}]
for i in inputs:
seed = Input(**i)
v = await text_to_embedding(seed.input)
assert len(v.data) > 0
def test_suite():
loop = asyncio.get_event_loop()
task = loop.create_task(mock_text_to_embedding())
loop.run_until_complete(task)
v = await text_to_embedding(text="Panda emoji")
assert len(v.data) > 0
if __name__ == "__main__":
test_suite()
pytest.main([__file__, "-s"])

View file

@ -24,9 +24,11 @@ async def test():
assert "base64" in data or "http" in data
key = CONFIG.METAGPT_TEXT_TO_IMAGE_MODEL_URL
CONFIG.METAGPT_TEXT_TO_IMAGE_MODEL_URL = None
data = await text_to_image("Panda emoji", size_type="512x512")
assert "base64" in data or "http" in data
CONFIG.METAGPT_TEXT_TO_IMAGE_MODEL_URL = key
try:
data = await text_to_image("Panda emoji", size_type="512x512")
assert "base64" in data or "http" in data
finally:
CONFIG.METAGPT_TEXT_TO_IMAGE_MODEL_URL = key
if __name__ == "__main__":

View file

@ -29,9 +29,11 @@ async def test_text_to_speech():
# test iflytek
key = CONFIG.AZURE_TTS_SUBSCRIPTION_KEY
CONFIG.AZURE_TTS_SUBSCRIPTION_KEY = ""
data = await text_to_speech("panda emoji")
assert "base64" in data or "http" in data
CONFIG.AZURE_TTS_SUBSCRIPTION_KEY = key
try:
data = await text_to_speech("panda emoji")
assert "base64" in data or "http" in data
finally:
CONFIG.AZURE_TTS_SUBSCRIPTION_KEY = key
if __name__ == "__main__":

View file

@ -58,6 +58,9 @@ async def test_memory_llm(llm):
res = await memory.rewrite(sentence="apple Lily eating", context="", llm=llm)
assert "Lily" in res
res = await memory.summarize(llm=llm)
assert res
res = await memory.get_title(llm=llm)
assert res
assert "Lily" in res

View file

@ -7,6 +7,8 @@
import os
import pytest
from metagpt.actions import UserRequirement
from metagpt.config import CONFIG
from metagpt.memory.longterm_memory import LongTermMemory
@ -63,3 +65,7 @@ def test_ltm_search():
assert len(news) == 1
ltm_new.clear()
if __name__ == "__main__":
pytest.main([__file__, "-s"])

View file

@ -5,6 +5,8 @@
@Author : alexanderwu
@File : mock_markdown.py
"""
import json
from metagpt.actions import UserRequirement, WriteDesign, WritePRD, WriteTasks
from metagpt.schema import Message
@ -151,6 +153,32 @@ sequenceDiagram
```
"""
JSON_TASKS = {
"Logic Analysis": """
在这个项目中所有的模块都依赖于SearchEngine这是主入口其他的模块IndexRanking和Summary都通过它交互另外"Index"类又依赖于"KnowledgeBase"因为它需要从知识库中获取数据
- "main.py"包含"Main"是程序的入口点它调用"SearchEngine"进行搜索操作所以在其他任何模块之前"SearchEngine"必须首先被定义
- "search.py"定义了"SearchEngine"它依赖于"Index""Ranking""Summary"因此这些模块需要在"search.py"之前定义
- "index.py"定义了"Index"它从"knowledge_base.py"获取数据来创建索引所以"knowledge_base.py"需要在"index.py"之前定义
- "ranking.py""summary.py"相对独立只需确保在"search.py"之前定义
- "knowledge_base.py"是独立的模块可以优先开发
- "interface.py""user_feedback.py""security.py""testing.py""monitoring.py"看起来像是功能辅助模块可以在主要功能模块开发完成后并行开发
""",
"Task list": [
"smart_search_engine/knowledge_base.py",
"smart_search_engine/index.py",
"smart_search_engine/ranking.py",
"smart_search_engine/summary.py",
"smart_search_engine/search.py",
"smart_search_engine/main.py",
"smart_search_engine/interface.py",
"smart_search_engine/user_feedback.py",
"smart_search_engine/security.py",
"smart_search_engine/testing.py",
"smart_search_engine/monitoring.py",
],
}
TASKS = """## Logic Analysis
@ -256,3 +284,4 @@ class MockMessages:
prd = Message(role="Product Manager", content=PRD, cause_by=WritePRD)
system_design = Message(role="Architect", content=SYSTEM_DESIGN, cause_by=WriteDesign)
tasks = Message(role="Project Manager", content=TASKS, cause_by=WriteTasks)
json_tasks = Message(role="Project Manager", content=json.dumps(JSON_TASKS), cause_by=WriteTasks)

View file

@ -6,6 +6,7 @@
@File : test_asssistant.py
@Desc : Used by AgentStore.
"""
import pytest
from pydantic import BaseModel
@ -90,10 +91,42 @@ async def test_run():
assert msg
assert msg.cause_by == seed.cause_by
assert msg.content
# # Retrieve user terminal input.
# logger.info("Enter prompt")
# talk = input("You: ")
# await role.talk(talk)
@pytest.mark.parametrize(
"memory",
[
{
"history": [
{
"content": "can you draw me an picture?",
"role": "user",
"id": "1",
},
{"content": "Yes, of course. What do you want me to draw", "role": "assistant"},
],
"knowledge": [{"content": "tulin is a scientist."}],
"last_talk": "Draw me an apple.",
}
],
)
@pytest.mark.asyncio
async def test_memory(memory):
role = Assistant()
role.load_memory(memory)
val = role.get_memory()
assert val
await role.talk("draw apple")
agent_skills = CONFIG.agent_skills
CONFIG.agent_skills = []
try:
await role.think()
finally:
CONFIG.agent_skills = agent_skills
assert isinstance(role.rc.todo, TalkAction)
if __name__ == "__main__":

View file

@ -7,30 +7,51 @@
@Modified By: mashenquan, 2023-11-1. In accordance with Chapter 2.2.1 and 2.2.2 of RFC 116, utilize the new message
distribution feature for message handling.
"""
import json
from pathlib import Path
import pytest
from metagpt.actions import WriteCode, WriteTasks
from metagpt.config import CONFIG
from metagpt.const import (
PRDS_FILE_REPO,
REQUIREMENT_FILENAME,
SYSTEM_DESIGN_FILE_REPO,
TASK_FILE_REPO,
)
from metagpt.logs import logger
from metagpt.roles.engineer import Engineer
from metagpt.utils.common import CodeParser
from metagpt.schema import CodingContext, Message
from metagpt.utils.common import CodeParser, any_to_name, any_to_str, aread, awrite
from metagpt.utils.file_repository import FileRepository
from metagpt.utils.git_repository import ChangeType
from tests.metagpt.roles.mock import STRS_FOR_PARSING, TASKS, MockMessages
@pytest.mark.asyncio
async def test_engineer():
engineer = Engineer()
# Prerequisites
rqno = "20231221155954.json"
await FileRepository.save_file(REQUIREMENT_FILENAME, content=MockMessages.req.content)
await FileRepository.save_file(rqno, relative_path=PRDS_FILE_REPO, content=MockMessages.prd.content)
await FileRepository.save_file(
rqno, relative_path=SYSTEM_DESIGN_FILE_REPO, content=MockMessages.system_design.content
)
await FileRepository.save_file(rqno, relative_path=TASK_FILE_REPO, content=MockMessages.json_tasks.content)
engineer.put_message(MockMessages.req)
engineer.put_message(MockMessages.prd)
engineer.put_message(MockMessages.system_design)
rsp = await engineer.run(MockMessages.tasks)
engineer = Engineer()
rsp = await engineer.run(Message(content="", cause_by=WriteTasks))
logger.info(rsp)
assert "all done." == rsp.content
assert rsp.cause_by == any_to_str(WriteCode)
src_file_repo = CONFIG.git_repo.new_file_repository(CONFIG.src_workspace)
assert src_file_repo.changed_files
def test_parse_str():
for idx, i in enumerate(STRS_FOR_PARSING):
text = CodeParser.parse_str(f"{idx+1}", i)
text = CodeParser.parse_str(f"{idx + 1}", i)
# logger.info(text)
assert text == "a"
@ -84,3 +105,59 @@ def test_parse_code():
logger.info(code)
assert isinstance(code, str)
assert target_code == code
def test_todo():
role = Engineer()
assert role.todo == any_to_name(WriteCode)
@pytest.mark.asyncio
async def test_new_coding_context():
# Prerequisites
demo_path = Path(__file__).parent / "../../data/demo_project"
deps = json.loads(await aread(demo_path / "dependencies.json"))
dependency = await CONFIG.git_repo.get_dependency()
for k, v in deps.items():
await dependency.update(k, set(v))
data = await aread(demo_path / "system_design.json")
rqno = "20231221155954.json"
await awrite(CONFIG.git_repo.workdir / SYSTEM_DESIGN_FILE_REPO / rqno, data)
data = await aread(demo_path / "tasks.json")
await awrite(CONFIG.git_repo.workdir / TASK_FILE_REPO / rqno, data)
CONFIG.src_workspace = Path(CONFIG.git_repo.workdir) / "game_2048"
src_file_repo = CONFIG.git_repo.new_file_repository(relative_path=CONFIG.src_workspace)
task_file_repo = CONFIG.git_repo.new_file_repository(relative_path=TASK_FILE_REPO)
design_file_repo = CONFIG.git_repo.new_file_repository(relative_path=SYSTEM_DESIGN_FILE_REPO)
filename = "game.py"
ctx_doc = await Engineer._new_coding_doc(
filename=filename,
src_file_repo=src_file_repo,
task_file_repo=task_file_repo,
design_file_repo=design_file_repo,
dependency=dependency,
)
assert ctx_doc
assert ctx_doc.filename == filename
assert ctx_doc.content
ctx = CodingContext.model_validate_json(ctx_doc.content)
assert ctx.filename == filename
assert ctx.design_doc
assert ctx.design_doc.content
assert ctx.task_doc
assert ctx.task_doc.content
assert ctx.code_doc
CONFIG.git_repo.add_change({f"{TASK_FILE_REPO}/{rqno}": ChangeType.UNTRACTED})
CONFIG.git_repo.commit("mock env")
await src_file_repo.save(filename=filename, content="content")
role = Engineer()
assert not role.code_todos
await role._new_code_actions()
assert role.code_todos
if __name__ == "__main__":
pytest.main([__file__, "-s"])

View file

@ -48,3 +48,7 @@ def test_write_report(mocker):
content = "# Research Report"
researcher.Researcher().write_report(topic, content)
assert (researcher.RESEARCH_PATH / f"{i+1}. metagpt.md").read_text().startswith("# Research Report")
if __name__ == "__main__":
pytest.main([__file__, "-s"])

View file

@ -1,6 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Desc : unittest of Role
import pytest
from metagpt.roles.role import Role
@ -9,3 +10,7 @@ def test_role_desc():
role = Role(profile="Sales", desc="Best Seller")
assert role.profile == "Sales"
assert role.desc == "Best Seller"
if __name__ == "__main__":
pytest.main([__file__, "-s"])

View file

@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
# @Date : 2023/7/22 02:40
# @Author : stellahong (stellahong@deepwisdom.ai)
#
from metagpt.roles import ProductManager
from metagpt.team import Team
from tests.metagpt.roles.ui_role import UI
def test_add_ui():
ui = UI()
assert ui.profile == "UI Design"
async def test_ui_role(idea: str, investment: float = 3.0, n_round: int = 5):
"""Run a startup. Be a boss."""
company = Team()
company.hire([ProductManager(), UI()])
company.invest(investment)
company.run_project(idea)
await company.run(n_round=n_round)

View file

@ -1,280 +0,0 @@
# -*- coding: utf-8 -*-
# @Date : 2023/7/15 16:40
# @Author : stellahong (stellahong@deepwisdom.ai)
# @Desc :
import os
import re
from functools import wraps
from importlib import import_module
from metagpt.actions import Action, ActionOutput, WritePRD
from metagpt.actions.action_node import ActionNode
from metagpt.config import CONFIG
from metagpt.logs import logger
from metagpt.roles import Role
from metagpt.schema import Message
from metagpt.tools.sd_engine import SDEngine
PROMPT_TEMPLATE = """
{context}
## Role
You are a UserInterface Designer; the goal is to finish a UI design according to PRD, give a design description, and select specified elements and UI style.
"""
UI_DESIGN_DESC = ActionNode(
key="UI Design Desc",
expected_type=str,
instruction="place the design objective here",
example="Snake games are classic and addictive games with simple yet engaging elements. Here are the main elements"
" commonly found in snake games",
)
SELECTED_ELEMENTS = ActionNode(
key="Selected Elements",
expected_type=list[str],
instruction="up to 5 specified elements, clear and simple",
example=[
"Game Grid: The game grid is a rectangular...",
"Snake: The player controls a snake that moves across the grid...",
"Food: Food items (often represented as small objects or differently colored blocks)",
"Score: The player's score increases each time the snake eats a piece of food. The longer the snake becomes, the higher the score.",
"Game Over: The game ends when the snake collides with itself or an obstacle. At this point, the player's final score is displayed, and they are given the option to restart the game.",
],
)
HTML_LAYOUT = ActionNode(
key="HTML Layout",
expected_type=str,
instruction="use standard HTML code",
example="""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Snake Game</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="game-grid">
<!-- Snake will be dynamically generated here using JavaScript -->
</div>
<div class="food">
<!-- Food will be dynamically generated here using JavaScript -->
</div>
</body>
</html>
""",
)
CSS_STYLES = ActionNode(
key="CSS Styles",
expected_type=str,
instruction="use standard css code",
example="""body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #f0f0f0;
}
.game-grid {
width: 400px;
height: 400px;
display: grid;
grid-template-columns: repeat(20, 1fr); /* Adjust to the desired grid size */
grid-template-rows: repeat(20, 1fr);
gap: 1px;
background-color: #222;
border: 1px solid #555;
}
.game-grid div {
width: 100%;
height: 100%;
background-color: #444;
}
.snake-segment {
background-color: #00cc66; /* Snake color */
}
.food {
width: 100%;
height: 100%;
background-color: #cc3300; /* Food color */
position: absolute;
}
/* Optional styles for a simple game over message */
.game-over {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 24px;
font-weight: bold;
color: #ff0000;
display: none;
}
""",
)
ANYTHING_UNCLEAR = ActionNode(
key="Anything UNCLEAR",
expected_type=str,
instruction="Mention any aspects of the project that are unclear and try to clarify them.",
example="...",
)
NODES = [
UI_DESIGN_DESC,
SELECTED_ELEMENTS,
HTML_LAYOUT,
CSS_STYLES,
ANYTHING_UNCLEAR,
]
UI_DESIGN_NODE = ActionNode.from_children("UI_DESIGN", NODES)
def load_engine(func):
"""Decorator to load an engine by file name and engine name."""
@wraps(func)
def wrapper(*args, **kwargs):
file_name, engine_name = func(*args, **kwargs)
engine_file = import_module(file_name, package="metagpt")
ip_module_cls = getattr(engine_file, engine_name)
try:
engine = ip_module_cls()
except:
engine = None
return engine
return wrapper
def parse(func):
"""Decorator to parse information using regex pattern."""
@wraps(func)
def wrapper(*args, **kwargs):
context, pattern = func(*args, **kwargs)
match = re.search(pattern, context, re.DOTALL)
if match:
text_info = match.group(1)
logger.info(text_info)
else:
text_info = context
logger.info("未找到匹配的内容")
return text_info
return wrapper
class UIDesign(Action):
"""Class representing the UI Design action."""
def __init__(self, name, context=None, llm=None):
super().__init__(name, context, llm) # 需要调用LLM进一步丰富UI设计的prompt
@parse
def parse_requirement(self, context: str):
"""Parse UI Design draft from the context using regex."""
pattern = r"## UI Design draft.*?\n(.*?)## Anything UNCLEAR"
return context, pattern
@parse
def parse_ui_elements(self, context: str):
"""Parse Selected Elements from the context using regex."""
pattern = r"## Selected Elements.*?\n(.*?)## HTML Layout"
return context, pattern
@parse
def parse_css_code(self, context: str):
pattern = r"```css.*?\n(.*?)## Anything UNCLEAR"
return context, pattern
@parse
def parse_html_code(self, context: str):
pattern = r"```html.*?\n(.*?)```"
return context, pattern
async def draw_icons(self, context, *args, **kwargs):
"""Draw icons using SDEngine."""
engine = SDEngine()
icon_prompts = self.parse_ui_elements(context)
icons = icon_prompts.split("\n")
icons = [s for s in icons if len(s.strip()) > 0]
prompts_batch = []
for icon_prompt in icons:
# fixme: 添加icon lora
prompt = engine.construct_payload(icon_prompt + ".<lora:WZ0710_AW81e-3_30e3b128d64T32_goon0.5>")
prompts_batch.append(prompt)
await engine.run_t2i(prompts_batch)
logger.info("Finish icon design using StableDiffusion API")
async def _save(self, css_content, html_content):
save_dir = CONFIG.workspace_path / "resources" / "codes"
if not os.path.exists(save_dir):
os.makedirs(save_dir, exist_ok=True)
# Save CSS and HTML content to files
css_file_path = save_dir / "ui_design.css"
html_file_path = save_dir / "ui_design.html"
css_file_path.write_text(css_content)
html_file_path.write_text(html_content)
async def run(self, requirements: list[Message], *args, **kwargs) -> ActionOutput:
"""Run the UI Design action."""
# fixme: update prompt (根据需求细化prompt
context = requirements[-1].content
ui_design_draft = self.parse_requirement(context=context)
# todo: parse requirements str
prompt = PROMPT_TEMPLATE.format(context=ui_design_draft)
logger.info(prompt)
ui_describe = await UI_DESIGN_NODE.fill(prompt)
logger.info(ui_describe.content)
logger.info(ui_describe.instruct_content)
css = self.parse_css_code(context=ui_describe.content)
html = self.parse_html_code(context=ui_describe.content)
await self._save(css_content=css, html_content=html)
await self.draw_icons(ui_describe.content)
return ui_describe
class UI(Role):
"""Class representing the UI Role."""
def __init__(
self,
name="Catherine",
profile="UI Design",
goal="Finish a workable and good User Interface design based on a product design",
constraints="Give clear layout description and use standard icons to finish the design",
skills=["SD"],
):
super().__init__(name, profile, goal, constraints)
self.load_skills(skills)
self._init_actions([UIDesign])
self._watch([WritePRD])
@load_engine
def load_sd_engine(self):
"""Load the SDEngine."""
file_name = ".tools.sd_engine"
engine_name = "SDEngine"
return file_name, engine_name
def load_skills(self, skills):
"""Load skills for the UI Role."""
# todo: 添加其他出图engine
for skill in skills:
if skill == "SD":
self.sd_engine = self.load_sd_engine()
logger.info(f"load skill engine {self.sd_engine}")

View file

@ -10,10 +10,20 @@
import json
import pytest
from metagpt.actions import Action
from metagpt.actions.action_node import ActionNode
from metagpt.actions.write_code import WriteCode
from metagpt.schema import AIMessage, Message, SystemMessage, UserMessage
from metagpt.config import CONFIG
from metagpt.schema import (
AIMessage,
Document,
Message,
MessageQueue,
SystemMessage,
UserMessage,
)
from metagpt.utils.common import any_to_str
@ -95,3 +105,32 @@ def test_message_serdeser():
new_message = Message(**message_dict)
assert new_message.instruct_content is None
assert new_message.cause_by == "metagpt.actions.add_requirement.UserRequirement"
assert not Message.load("{")
def test_document():
doc = Document(root_path="a", filename="b", content="c")
meta_doc = doc.get_meta()
assert doc.root_path == meta_doc.root_path
assert doc.filename == meta_doc.filename
assert meta_doc.content == ""
assert doc.full_path == str(CONFIG.git_repo.workdir / doc.root_path / doc.filename)
@pytest.mark.asyncio
async def test_message_queue():
mq = MessageQueue()
mq.push(Message(content="1"))
mq.push(Message(content="2中文测试aaa"))
msg = mq.pop()
assert msg.content == "1"
val = await mq.dump()
assert val
new_mq = MessageQueue.load(val)
assert new_mq.pop_all() == mq.pop_all()
if __name__ == "__main__":
pytest.main([__file__, "-s"])

View file

@ -53,7 +53,8 @@ async def test_dependency_file():
file1 = DependencyFile(workdir=Path(__file__).parent)
assert file1.exists
assert await file1.get("a/b.txt") == set()
assert await file1.get("a/b.txt", persist=False) == set()
assert await file1.get("a/b.txt") == {"c/e.txt", "d.txt"}
await file1.load()
assert await file1.get("a/b.txt") == {"c/e.txt", "d.txt"}
file1.delete_file()

View file

@ -15,7 +15,13 @@ from metagpt.utils.file import File
@pytest.mark.asyncio
@pytest.mark.parametrize(
("root_path", "filename", "content"),
[(Path("/code/MetaGPT/data/tutorial_docx/2023-09-07_17-05-20"), "test.md", "Hello World!")],
[
(
Path(__file__).parent / "../../../workspace/unittest/data/tutorial_docx/2023-09-07_17-05-20",
"test.md",
"Hello World!",
)
],
)
async def test_write_and_read_file(root_path: Path, filename: str, content: bytes):
full_file_name = await File.write(root_path=root_path, filename=filename, content=content.encode("utf-8"))

View file

@ -47,9 +47,11 @@ async def test_s3_no_error():
conn = S3()
key = conn.auth_config["aws_secret_access_key"]
conn.auth_config["aws_secret_access_key"] = ""
res = await conn.cache("ABC", ".bak", "script")
assert not res
conn.auth_config["aws_secret_access_key"] = key
try:
res = await conn.cache("ABC", ".bak", "script")
assert not res
finally:
conn.auth_config["aws_secret_access_key"] = key
if __name__ == "__main__":