166 const std::string& path) {
170 root[
"name"] = script.
name;
172 root[
"created_at"] = FormatIsoTimestamp(script.
created_at);
173 root[
"duration_ms"] = absl::ToInt64Milliseconds(script.
duration);
175 nlohmann::json steps_json = nlohmann::json::array();
176 for (
const auto& step : script.
steps) {
177 nlohmann::json step_node(nlohmann::json::value_t::object);
178 PopulateStepNode(step, &step_node);
179 steps_json.push_back(std::move(step_node));
181 root[
"steps"] = std::move(steps_json);
183 std::filesystem::path output_path(path);
185 auto parent = output_path.parent_path();
186 if (!parent.empty() && !std::filesystem::exists(parent)) {
187 if (!std::filesystem::create_directories(parent, ec)) {
188 return absl::InternalError(
189 absl::StrFormat(
"Failed to create directory '%s': %s",
190 parent.string(), ec.message()));
194 std::ofstream ofs(output_path, std::ios::out | std::ios::trunc);
196 return absl::InternalError(
197 absl::StrFormat(
"Failed to open '%s' for writing", path));
199 ofs << root.dump(2) <<
'\n';
200 return absl::OkStatus();
204 const std::string& path) {
205 std::ifstream ifs(path);
207 return absl::NotFoundError(
208 absl::StrFormat(
"Test script '%s' not found", path));
214 }
catch (
const nlohmann::json::exception& e) {
215 return absl::InvalidArgumentError(
216 absl::StrFormat(
"Failed to parse JSON: %s", e.what()));
221 root.contains(
"schema_version") ? root[
"schema_version"].get<
int>() : 1;
224 return absl::InvalidArgumentError(absl::StrFormat(
225 "Unsupported test script schema version %d", script.
schema_version));
228 if (root.contains(
"recording_id")) {
229 script.
recording_id = root[
"recording_id"].get<std::string>();
231 if (root.contains(
"name")) {
232 script.
name = root[
"name"].get<std::string>();
234 if (root.contains(
"description")) {
235 script.
description = root[
"description"].get<std::string>();
239 if (root.contains(
"duration_ms")) {
240 script.
duration = absl::Milliseconds(root[
"duration_ms"].get<int64_t>());
243 if (!root.contains(
"steps") || !root[
"steps"].is_array()) {
244 return absl::InvalidArgumentError(
245 "Test script missing required array field 'steps'");
248 for (
const auto& step_node : root[
"steps"]) {
250 script.
steps.push_back(std::move(step));