use crate::core::config::ResolvedCrateConfig;
use crate::core::hash::{self, CommentStyle};
use crate::e2e::config::E2eConfig;
use crate::e2e::field_access::SwiftFirstClassMap;
use crate::e2e::fixture::Fixture;
use std::fmt::Write as FmtWrite;
use super::project::SWIFT_FORMAT_IGNORE_DIRECTIVE;
use super::{http, test_method};
#[allow(clippy::too_many_arguments)]
pub(super) fn render_test_file(
category: &str,
fixtures: &[&Fixture],
e2e_config: &E2eConfig,
module_name: &str,
class_name: &str,
function_name: &str,
result_var: &str,
args: &[crate::e2e::config::ArgMapping],
result_is_simple: bool,
client_factory: Option<&str>,
swift_first_class_map: &SwiftFirstClassMap,
config: &ResolvedCrateConfig,
type_defs: &[crate::core::ir::TypeDef],
has_http_fixtures: bool,
enums: &[crate::core::ir::EnumDef],
) -> String {
let needs_chdir = fixtures.iter().any(|f| {
let call_config =
e2e_config.resolve_call_for_fixture(f.call.as_deref(), &f.id, &f.resolved_category(), &f.tags, &f.input);
call_config
.args
.iter()
.any(|a| a.arg_type == "file_path" || a.arg_type == "bytes")
});
let mut out = String::new();
out.push_str(&hash::header(CommentStyle::DoubleSlash));
out.push_str(SWIFT_FORMAT_IGNORE_DIRECTIVE);
let _ = writeln!(out, "import XCTest");
let _ = writeln!(out, "import Foundation");
let _ = writeln!(out, "#if canImport(FoundationNetworking)");
let _ = writeln!(out, "import FoundationNetworking");
let _ = writeln!(out, "#endif");
let _ = writeln!(out, "import {module_name}");
let _ = writeln!(out, "import RustBridge");
let _ = writeln!(out);
let _ = writeln!(out, "/// E2e tests for category: {category}.");
let _ = writeln!(out, "final class {class_name}: XCTestCase {{");
let _ = writeln!(out, " override class func setUp() {{");
let _ = writeln!(out, " super.setUp()");
let _ = writeln!(
out,
" let _existing = ProcessInfo.processInfo.environment[\"SUT_URL\"]"
);
if has_http_fixtures {
let _ = writeln!(out, " if _existing == nil {{");
let _ = writeln!(out, " let _harness = URL(fileURLWithPath: #filePath)");
let _ = writeln!(out, " .deletingLastPathComponent() // <Module>Tests/");
let _ = writeln!(out, " .deletingLastPathComponent() // Tests/");
let _ = writeln!(out, " .deletingLastPathComponent() // swift_e2e/");
let _ = writeln!(out, " .deletingLastPathComponent() // e2e/");
let _ = writeln!(out, " .appendingPathComponent(\"swift_e2e\")");
let _ = writeln!(out, " .appendingPathComponent(\".build/debug/Harness\")");
let _ = writeln!(out, " let proc = Process()");
let _ = writeln!(out, " proc.executableURL = _harness");
let _ = writeln!(out, " let stdoutPipe = Pipe()");
let _ = writeln!(out, " proc.standardOutput = stdoutPipe");
let _ = writeln!(out, " proc.standardInput = Pipe()");
let _ = writeln!(out, " do {{");
let _ = writeln!(out, " try proc.run()");
let _ = writeln!(out, " }} catch {{");
let _ = writeln!(
out,
" fatalError(\"Failed to start harness: \\(error)\")"
);
let _ = writeln!(out, " }}");
let _ = writeln!(out, " let deadline = Date(timeIntervalSinceNow: 15.0)");
let _ = writeln!(out, " var ready = false");
let host = &e2e_config.harness.host;
let port = e2e_config.harness.port;
let _ = writeln!(
out,
" let _probeURL = URL(string: \"http://{}:{}/\")!",
host, port
);
let _ = writeln!(out, " while Date.now < deadline {{");
let _ = writeln!(out, " if proc.isRunning == false {{ break }}");
let _ = writeln!(out, " var _probeReq = URLRequest(url: _probeURL)");
let _ = writeln!(out, " _probeReq.timeoutInterval = 0.5");
let _ = writeln!(out, " let _probeSema = DispatchSemaphore(value: 0)");
let _ = writeln!(
out,
" let _probeSession = URLSession(configuration: .ephemeral)"
);
let _ = writeln!(
out,
" _probeSession.dataTask(with: _probeReq) {{ _, _, _ in _probeSema.signal() }}.resume()"
);
let _ = writeln!(
out,
" if _probeSema.wait(timeout: .now() + 0.6) == .timedOut {{"
);
let _ = writeln!(out, " usleep(100000)");
let _ = writeln!(out, " continue");
let _ = writeln!(out, " }}");
let _ = writeln!(out, " ready = true");
let _ = writeln!(out, " break");
let _ = writeln!(out, " }}");
let _ = writeln!(out, " if !ready {{");
let _ = writeln!(out, " proc.terminate()");
let _ = writeln!(
out,
" fatalError(\"Harness did not become ready within 15s\")"
);
let _ = writeln!(out, " }}");
let _ = writeln!(
out,
" _ = \"http://{}:{}\".withCString {{ url in",
host, port
);
let _ = writeln!(out, " \"SUT_URL\".withCString {{ key in");
let _ = writeln!(out, " setenv(key, url, 1)");
let _ = writeln!(out, " }}");
let _ = writeln!(out, " }}");
let _ = writeln!(out, " }}");
}
if needs_chdir {
let _ = writeln!(out, " let _testDocs = URL(fileURLWithPath: #filePath)");
let _ = writeln!(out, " .deletingLastPathComponent() // <Module>Tests/");
let _ = writeln!(out, " .deletingLastPathComponent() // Tests/");
let _ = writeln!(out, " .deletingLastPathComponent() // swift_e2e/");
let _ = writeln!(out, " .deletingLastPathComponent() // e2e/");
let _ = writeln!(out, " .deletingLastPathComponent() // <repo root>");
let _ = writeln!(
out,
" .appendingPathComponent(\"{}\")",
e2e_config.test_documents_dir
);
let _ = writeln!(
out,
" if FileManager.default.fileExists(atPath: _testDocs.path) {{"
);
let _ = writeln!(
out,
" FileManager.default.changeCurrentDirectoryPath(_testDocs.path)"
);
let _ = writeln!(out, " }}");
}
let _ = writeln!(out, " }}");
let _ = writeln!(out);
for fixture in fixtures {
if fixture.is_http_test() {
http::render_http_test_method(&mut out, fixture);
} else {
test_method::render_test_method(
&mut out,
fixture,
e2e_config,
function_name,
result_var,
args,
result_is_simple,
client_factory,
swift_first_class_map,
module_name,
config,
type_defs,
enums,
);
}
let _ = writeln!(out);
}
let _ = writeln!(out, "}}");
out
}