forked from MakazhanAlpamys/Soup
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_generate.py
More file actions
224 lines (167 loc) · 7.74 KB
/
Copy pathtest_generate.py
File metadata and controls
224 lines (167 loc) · 7.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
"""Tests for soup data generate — synthetic data generation."""
import json
class TestParseJsonArray:
"""Test JSON array parsing from LLM output."""
def test_parse_clean_json_array(self):
"""Should parse a clean JSON array."""
from soup_cli.commands.generate import _parse_json_array
content = json.dumps([
{"instruction": "What is AI?", "input": "", "output": "AI is..."},
{"instruction": "Explain ML", "input": "", "output": "ML is..."},
])
result = _parse_json_array(content)
assert len(result) == 2
assert result[0]["instruction"] == "What is AI?"
def test_parse_json_with_markdown_fences(self):
"""Should strip markdown code fences."""
from soup_cli.commands.generate import _parse_json_array
content = '```json\n[{"instruction": "test", "input": "", "output": "ok"}]\n```'
result = _parse_json_array(content)
assert len(result) == 1
assert result[0]["instruction"] == "test"
def test_parse_json_with_extra_text(self):
"""Should extract JSON array from surrounding text."""
from soup_cli.commands.generate import _parse_json_array
content = (
'Here are the examples:\n'
'[{"instruction": "a", "input": "", "output": "b"}]\nDone!'
)
result = _parse_json_array(content)
assert len(result) == 1
def test_parse_empty_content(self):
"""Should return empty list for empty content."""
from soup_cli.commands.generate import _parse_json_array
result = _parse_json_array("")
assert result == []
def test_parse_jsonl_fallback(self):
"""Should fall back to line-by-line JSON parsing."""
from soup_cli.commands.generate import _parse_json_array
content = (
'{"instruction": "a", "input": "", "output": "b"}\n'
'{"instruction": "c", "input": "", "output": "d"}'
)
result = _parse_json_array(content)
assert len(result) == 2
def test_parse_invalid_json(self):
"""Should return empty list for completely invalid JSON."""
from soup_cli.commands.generate import _parse_json_array
result = _parse_json_array("this is not json at all")
assert result == []
def test_parse_filters_non_dicts(self):
"""Should filter out non-dict items."""
from soup_cli.commands.generate import _parse_json_array
content = '[{"instruction": "a", "input": "", "output": "b"}, "string", 42]'
result = _parse_json_array(content)
assert len(result) == 1
class TestValidateExample:
"""Test example validation."""
def test_validate_alpaca_valid(self):
"""Valid alpaca format should pass."""
from soup_cli.commands.generate import _validate_example
example = {"instruction": "test", "input": "", "output": "ok"}
assert _validate_example(example, "alpaca") is True
def test_validate_alpaca_missing_fields(self):
"""Alpaca missing required fields should fail."""
from soup_cli.commands.generate import _validate_example
assert _validate_example({"instruction": "test"}, "alpaca") is False
assert _validate_example({"output": "test"}, "alpaca") is False
def test_validate_sharegpt_valid(self):
"""Valid sharegpt format should pass."""
from soup_cli.commands.generate import _validate_example
example = {
"conversations": [
{"from": "human", "value": "Hi"},
{"from": "gpt", "value": "Hello!"},
]
}
assert _validate_example(example, "sharegpt") is True
def test_validate_sharegpt_too_few(self):
"""Sharegpt with fewer than 2 messages should fail."""
from soup_cli.commands.generate import _validate_example
example = {"conversations": [{"from": "human", "value": "Hi"}]}
assert _validate_example(example, "sharegpt") is False
def test_validate_chatml_valid(self):
"""Valid chatml format should pass."""
from soup_cli.commands.generate import _validate_example
example = {
"messages": [
{"role": "user", "content": "Hi"},
{"role": "assistant", "content": "Hello!"},
]
}
assert _validate_example(example, "chatml") is True
def test_validate_chatml_empty(self):
"""Chatml with empty messages should fail."""
from soup_cli.commands.generate import _validate_example
assert _validate_example({"messages": []}, "chatml") is False
def test_validate_unknown_format(self):
"""Unknown format should fail."""
from soup_cli.commands.generate import _validate_example
assert _validate_example({"data": "test"}, "unknown") is False
class TestBuildGenerationPrompt:
"""Test generation prompt building."""
def test_prompt_includes_format_spec(self):
"""Prompt should include format specification."""
from soup_cli.commands.generate import _build_generation_prompt
result = _build_generation_prompt("Create math questions", 5, "alpaca", [])
assert "instruction" in result
assert "output" in result
assert "5" in result
def test_prompt_includes_seed_examples(self):
"""Prompt should include seed examples when provided."""
from soup_cli.commands.generate import _build_generation_prompt
seeds = [{"instruction": "example", "input": "", "output": "test"}]
result = _build_generation_prompt("Create data", 3, "alpaca", seeds)
assert "example" in result
assert "seed" in result.lower()
def test_prompt_sharegpt_format(self):
"""Prompt should describe sharegpt format correctly."""
from soup_cli.commands.generate import _build_generation_prompt
result = _build_generation_prompt("Create chats", 3, "sharegpt", [])
assert "conversations" in result
def test_prompt_chatml_format(self):
"""Prompt should describe chatml format correctly."""
from soup_cli.commands.generate import _build_generation_prompt
result = _build_generation_prompt("Create chats", 3, "chatml", [])
assert "messages" in result
class TestRowToText:
"""Test row to text conversion for dedup."""
def test_row_to_text_basic(self):
"""Should concatenate all values."""
from soup_cli.commands.generate import _row_to_text
row = {"instruction": "What is AI?", "output": "AI is..."}
text = _row_to_text(row)
assert "What is AI?" in text
assert "AI is..." in text
def test_row_to_text_empty_values(self):
"""Should skip empty values."""
from soup_cli.commands.generate import _row_to_text
row = {"instruction": "test", "input": "", "output": "ok"}
text = _row_to_text(row)
assert "test" in text
class TestGenerateCLI:
"""Test CLI integration for generate command."""
def test_invalid_format_rejected(self):
"""Should reject invalid format."""
from typer.testing import CliRunner
from soup_cli.cli import app
runner = CliRunner()
result = runner.invoke(app, [
"data", "generate",
"--prompt", "test",
"--format", "invalid_format",
"--count", "1",
])
assert result.exit_code != 0
def test_invalid_provider_rejected(self):
"""Should reject invalid provider."""
from typer.testing import CliRunner
from soup_cli.cli import app
runner = CliRunner()
result = runner.invoke(app, [
"data", "generate",
"--prompt", "test",
"--provider", "invalid_provider",
"--count", "1",
])
assert result.exit_code != 0