2Tests for csv_to_eng module.
6from pathlib
import Path
10from csv_to_eng
import (
21 """Tests for EngineMetadata dataclass."""
25 assert meta.name ==
"Unknown"
26 assert meta.diameter_mm == 0.0
27 assert meta.manufacturer ==
"Unknown"
37 manufacturer=
"Acme Rocketry",
39 header = meta.header_line()
40 assert header ==
"K1000 54 326 6-10-14 0.8500 1.4500 Acme_Rocketry"
44 header = meta.header_line()
45 assert "My_Motor" in header
46 assert "Space_Co" in header
50 """Tests for read_csv_curve function."""
53 csv_content =
"""time,thrust
59 with tempfile.NamedTemporaryFile(mode=
"w", suffix=
".csv", delete=
False)
as f:
64 metadata, points = read_csv_curve(csv_path)
65 assert len(points) == 4
66 assert points[0] == (0.0, 0.0)
67 assert points[1] == (0.1, 100.5)
68 assert points[3] == (0.3, 0.0)
70 Path(csv_path).unlink()
77 with tempfile.NamedTemporaryFile(mode=
"w", suffix=
".csv", delete=
False)
as f:
82 metadata, points = read_csv_curve(csv_path)
83 assert len(points) == 2
84 assert points[1] == (0.5, 200.0)
86 Path(csv_path).unlink()
89 csv_content =
"""# This is a comment
95 with tempfile.NamedTemporaryFile(mode=
"w", suffix=
".csv", delete=
False)
as f:
100 metadata, points = read_csv_curve(csv_path)
101 assert len(points) == 2
103 Path(csv_path).unlink()
106 csv_content =
"""time,thrust,temperature,pressure
110 with tempfile.NamedTemporaryFile(mode=
"w", suffix=
".csv", delete=
False)
as f:
115 metadata, points = read_csv_curve(csv_path)
116 assert len(points) == 2
117 assert points[0] == (0.0, 0.0)
118 assert points[1] == (0.1, 100.0)
120 Path(csv_path).unlink()
123 csv_content =
"""time,thrust,engine_name,diameter_mm,length_mm,manufacturer
1240.0,0.0,K500,38,200,TestCo
127 with tempfile.NamedTemporaryFile(mode=
"w", suffix=
".csv", delete=
False)
as f:
132 metadata, points = read_csv_curve(csv_path)
133 assert metadata.name ==
"K500"
134 assert metadata.diameter_mm == 38.0
135 assert metadata.length_mm == 200.0
136 assert metadata.manufacturer ==
"TestCo"
138 Path(csv_path).unlink()
141 csv_content =
"""time_ms,thrust
146 with tempfile.NamedTemporaryFile(mode=
"w", suffix=
".csv", delete=
False)
as f:
151 metadata, points = read_csv_curve(csv_path)
152 assert points[0] == (0.0, 0.0)
153 assert points[1] == (0.1, 100.0)
154 assert points[2] == (0.2, 0.0)
156 Path(csv_path).unlink()
159 csv_content =
"""time,thrust_lbf
163 with tempfile.NamedTemporaryFile(mode=
"w", suffix=
".csv", delete=
False)
as f:
168 metadata, points = read_csv_curve(csv_path)
169 expected_thrust_n = 10.0 * LBF_TO_N
170 assert abs(points[1][1] - expected_thrust_n) < 0.01
172 Path(csv_path).unlink()
175 csv_content =
"""time,thrust
179 with tempfile.NamedTemporaryFile(mode=
"w", suffix=
".csv", delete=
False)
as f:
185 metadata, points = read_csv_curve(csv_path, time_units=
"ms", thrust_units=
"lbf")
186 assert points[1][0] == 0.1
187 expected_thrust = 22.5 * LBF_TO_N
188 assert abs(points[1][1] - expected_thrust) < 0.01
190 Path(csv_path).unlink()
193 csv_content =
"""time,thrust
197 with tempfile.NamedTemporaryFile(mode=
"w", suffix=
".csv", delete=
False)
as f:
202 metadata, points = read_csv_curve(csv_path)
203 assert points[0][1] == 0.0
205 Path(csv_path).unlink()
208 csv_content =
"""time,thrust
212 with tempfile.NamedTemporaryFile(mode=
"w", suffix=
".csv", delete=
False)
as f:
217 with pytest.raises(ValueError, match=
"Negative time"):
218 read_csv_curve(csv_path)
220 Path(csv_path).unlink()
224 csv_content =
"""0.0,0.0
228 with tempfile.NamedTemporaryFile(mode=
"w", suffix=
".csv", delete=
False)
as f:
233 metadata, points = read_csv_curve(csv_path)
234 assert len(points) == 3
235 assert points[1] == (0.1, 100.0)
237 Path(csv_path).unlink()
240 csv_content =
""" time , thrust
244 with tempfile.NamedTemporaryFile(mode=
"w", suffix=
".csv", delete=
False)
as f:
249 metadata, points = read_csv_curve(csv_path)
250 assert len(points) == 2
252 Path(csv_path).unlink()
256 """Tests for normalize_curve function."""
259 """Curve already starts at 0 and ends at 0."""
260 points = [(0.0, 0.0), (0.1, 100.0), (0.2, 0.0)]
261 normalized = normalize_curve(points)
262 assert normalized == [(0.0, 0.0), (0.1, 100.0), (0.2, 0.0)]
265 """Insert t=0 if curve doesn't start there."""
266 points = [(0.05, 100.0), (0.1, 150.0), (0.2, 0.0)]
267 normalized = normalize_curve(points)
268 assert normalized[0] == (0.0, 0.0)
269 assert normalized[1] == (0.05, 100.0)
272 """Append thrust=0 at end if curve doesn't end at 0."""
273 points = [(0.0, 0.0), (0.1, 100.0), (0.2, 50.0)]
274 normalized = normalize_curve(points)
275 assert normalized[-1][1] == 0.0
276 assert normalized[-1][0] > 0.2
279 """Unsorted points should be sorted by time."""
280 points = [(0.2, 50.0), (0.0, 0.0), (0.1, 100.0), (0.15, 120.0)]
281 normalized = normalize_curve(points)
282 times = [p[0]
for p
in normalized]
283 assert times == sorted(times)
286 """Duplicate times should keep the last value."""
287 points = [(0.0, 0.0), (0.1, 100.0), (0.1, 150.0), (0.2, 0.0)]
288 normalized = normalize_curve(points)
290 t_01_point = [p
for p
in normalized
if p[0] == 0.1][0]
291 assert t_01_point[1] == 150.0
294 """Values should be rounded appropriately."""
295 points = [(0.0, 0.0), (0.12345, 100.5678)]
296 normalized = normalize_curve(points, time_decimals=3, thrust_decimals=1)
299 mid_point = [p
for p
in normalized
if 0.12 < p[0] < 0.13][0]
300 assert mid_point[0] == 0.123
301 assert mid_point[1] == 100.6
304 """Empty input should return minimal valid curve."""
305 normalized = normalize_curve([])
306 assert normalized == [(0.0, 0.0)]
310 """Tests for write_eng function."""
320 manufacturer=
"TestMfr",
322 points = [(0.0, 0.0), (0.1, 100.0), (0.2, 0.0)]
324 with tempfile.NamedTemporaryFile(mode=
"w", suffix=
".eng", delete=
False)
as f:
328 write_eng(eng_path, metadata, points)
330 content = Path(eng_path).read_text()
331 lines = content.strip().
split(
"\n")
334 assert lines[0].startswith(
";")
337 assert "TestMotor 29 124 5 0.0500 0.1000 TestMfr" in lines[1]
340 assert "0.000 0.0" in lines[2]
341 assert "0.100 100.0" in lines[3]
342 assert "0.200 0.0" in lines[4]
344 Path(eng_path).unlink()
348 """Tests for the high-level convert function."""
351 csv_content =
"""time,thrust
357 with tempfile.NamedTemporaryFile(mode=
"w", suffix=
".csv", delete=
False)
as f:
361 eng_path = csv_path.replace(
".csv",
".eng")
370 manufacturer=
"PyTest",
373 content = Path(eng_path).read_text()
374 assert "TestEngine" in content
375 assert "38" in content
376 assert "PyTest" in content
379 lines = content.strip().
split(
"\n")
380 last_line = lines[-1]
381 assert last_line.endswith(
" 0.0")
384 Path(csv_path).unlink()
385 if Path(eng_path).exists():
386 Path(eng_path).unlink()
390 csv_content =
"""time,thrust
395 with tempfile.NamedTemporaryFile(mode=
"w", suffix=
".csv", delete=
False)
as f:
399 eng_path = csv_path.replace(
".csv",
".eng")
409 content = Path(eng_path).read_text()
410 lines = content.strip().
split(
"\n")
413 assert "0.100" in lines[3]
417 thrust_val = float(data_line.split()[1])
418 expected = 10.0 * LBF_TO_N
419 assert abs(thrust_val - expected) < 0.1
422 Path(csv_path).unlink()
423 if Path(eng_path).exists():
424 Path(eng_path).unlink()
428 """Tests for CLI functionality."""
433 csv_content =
"""time,thrust
438 with tempfile.NamedTemporaryFile(mode=
"w", suffix=
".csv", delete=
False)
as f:
442 eng_path = csv_path.replace(
".csv",
".eng")
447 "--output", eng_path,
451 assert exit_code == 0
452 assert Path(eng_path).exists()
453 content = Path(eng_path).read_text()
454 assert "CLITest" in content
457 Path(csv_path).unlink()
458 if Path(eng_path).exists():
459 Path(eng_path).unlink()
465 "--input",
"/nonexistent/file.csv",
466 "--output",
"/tmp/output.eng",
469 assert exit_code == 1
test_cli_missing_file(self)
test_full_conversion(self)
test_conversion_with_unit_override(self)
test_duplicate_times_kept_last(self)
test_already_normalized(self)
test_append_zero_end(self)
test_insert_zero_start(self)
test_comment_lines_ignored(self)
test_lbf_conversion(self)
test_metadata_extraction(self)
test_explicit_unit_override(self)
test_extra_columns_ignored(self)
test_negative_thrust_clamped(self)
test_milliseconds_conversion(self)
test_no_header_assumes_time_thrust(self)
test_whitespace_handling(self)
test_alternative_column_names(self)
test_negative_time_raises_error(self)
static std::vector< string_t > split(const string_t &reference_string)
split the string input to reference tokens
json_pointer< string_t > convert() const &