160 const std::string& path) {
164 root[
"name"] = script.
name;
166 root[
"created_at"] = FormatIsoTimestamp(script.
created_at);
167 root[
"duration_ms"] = absl::ToInt64Milliseconds(script.
duration);
169 nlohmann::json steps_json = nlohmann::json::array();
170 for (
const auto& step : script.
steps) {
171 nlohmann::json step_node(nlohmann::json::value_t::object);
172 PopulateStepNode(step, &step_node);
173 steps_json.push_back(std::move(step_node));
175 root[
"steps"] = std::move(steps_json);
177 std::filesystem::path output_path(path);
179 auto parent = output_path.parent_path();
180 if (!parent.empty() && !std::filesystem::exists(parent)) {
181 if (!std::filesystem::create_directories(parent, ec)) {
182 return absl::InternalError(absl::StrFormat(
183 "Failed to create directory '%s': %s", parent.string(), ec.message()));
187 std::ofstream ofs(output_path, std::ios::out | std::ios::trunc);
189 return absl::InternalError(
190 absl::StrFormat(
"Failed to open '%s' for writing", path));
192 ofs << root.dump(2) <<
'\n';
193 return absl::OkStatus();
197 const std::string& path) {
198 std::ifstream ifs(path);
200 return absl::NotFoundError(
201 absl::StrFormat(
"Test script '%s' not found", path));
207 }
catch (
const nlohmann::json::exception& e) {
208 return absl::InvalidArgumentError(
209 absl::StrFormat(
"Failed to parse JSON: %s", e.what()));
214 root.contains(
"schema_version") ? root[
"schema_version"].get<
int>() : 1;
217 return absl::InvalidArgumentError(absl::StrFormat(
218 "Unsupported test script schema version %d", script.
schema_version));
221 if (root.contains(
"recording_id")) {
222 script.
recording_id = root[
"recording_id"].get<std::string>();
224 if (root.contains(
"name")) {
225 script.
name = root[
"name"].get<std::string>();
227 if (root.contains(
"description")) {
228 script.
description = root[
"description"].get<std::string>();
232 ParseIsoTimestamp(root,
"created_at"));
233 if (root.contains(
"duration_ms")) {
234 script.
duration = absl::Milliseconds(root[
"duration_ms"].get<int64_t>());
237 if (!root.contains(
"steps") || !root[
"steps"].is_array()) {
238 return absl::InvalidArgumentError(
239 "Test script missing required array field 'steps'");
242 for (
const auto& step_node : root[
"steps"]) {
244 script.
steps.push_back(std::move(step));