mirror of
https://github.com/ziex-dev/ziex.git
synced 2026-07-21 02:59:36 -06:00
370 lines
12 KiB
Zig
370 lines
12 KiB
Zig
test "init" {
|
|
// Create test/tmp directory
|
|
const test_dir = "test/tmp";
|
|
try std.fs.cwd().makePath(test_dir);
|
|
|
|
// Get absolute path for test directory
|
|
const test_dir_abs = try std.fs.cwd().realpathAlloc(allocator, test_dir);
|
|
defer allocator.free(test_dir_abs);
|
|
|
|
// Get absolute path for zx binary
|
|
const zx_bin_rel = if (builtin.os.tag == .windows) "zig-out/bin/zx.exe" else "zig-out/bin/zx";
|
|
const zx_bin_abs = try std.fs.cwd().realpathAlloc(allocator, zx_bin_rel);
|
|
defer allocator.free(zx_bin_abs);
|
|
|
|
// Initialize child process with cwd set to test/tmp
|
|
var child = std.process.Child.init(&.{ zx_bin_abs, "init" }, allocator);
|
|
child.cwd = test_dir_abs;
|
|
child.stdout_behavior = .Pipe;
|
|
child.stderr_behavior = .Pipe;
|
|
try child.spawn();
|
|
|
|
var stdout = std.ArrayList(u8).empty;
|
|
var stderr = std.ArrayList(u8).empty;
|
|
defer stdout.deinit(allocator);
|
|
defer stderr.deinit(allocator);
|
|
try child.collectOutput(allocator, &stdout, &stderr, 8192);
|
|
// std.debug.print("stdout: {s}\n", .{stdout.items});
|
|
// std.debug.print("stderr: {s}\n", .{stderr.items});
|
|
|
|
// Verify that build.zig.zon was created
|
|
const build_zig_zon_path = try std.fs.path.join(allocator, &.{ test_dir_abs, "build.zig.zon" });
|
|
defer allocator.free(build_zig_zon_path);
|
|
|
|
const file = try std.fs.openFileAbsolute(build_zig_zon_path, .{});
|
|
defer file.close();
|
|
|
|
const stat = try file.stat();
|
|
try std.testing.expect(stat.kind == .file);
|
|
|
|
const expected_strings = [_][]const u8{
|
|
"Initializing ZX project!",
|
|
"build.zig.zon",
|
|
"build.zig",
|
|
"site/main.zig",
|
|
".gitignore",
|
|
"README.md",
|
|
};
|
|
|
|
for (expected_strings) |expected_string| {
|
|
try std.testing.expect(std.mem.indexOf(u8, stderr.items, expected_string) != null);
|
|
}
|
|
}
|
|
|
|
test "init → init" {
|
|
const zx_bin_abs = try getZxPath();
|
|
const test_dir_abs = try getTestDirPath();
|
|
defer allocator.free(zx_bin_abs);
|
|
defer allocator.free(test_dir_abs);
|
|
|
|
var child = std.process.Child.init(&.{ zx_bin_abs, "init" }, allocator);
|
|
child.cwd = test_dir_abs;
|
|
child.stdout_behavior = .Pipe;
|
|
child.stderr_behavior = .Pipe;
|
|
try child.spawn();
|
|
|
|
var stdout = std.ArrayList(u8).empty;
|
|
var stderr = std.ArrayList(u8).empty;
|
|
defer stdout.deinit(allocator);
|
|
defer stderr.deinit(allocator);
|
|
try child.collectOutput(allocator, &stdout, &stderr, 8192);
|
|
|
|
// std.debug.print("stdout: {s}\n", .{stdout.items});
|
|
// std.debug.print("stderr: {s}\n", .{stderr.items});
|
|
|
|
try std.testing.expect(std.mem.indexOf(u8, stderr.items, "Directory is not empty") != null);
|
|
}
|
|
|
|
test "init --force" {
|
|
const zx_bin_abs = try getZxPath();
|
|
const test_dir_abs = try getTestDirPath();
|
|
defer allocator.free(zx_bin_abs);
|
|
defer allocator.free(test_dir_abs);
|
|
|
|
var child = std.process.Child.init(&.{ zx_bin_abs, "init", "--force" }, allocator);
|
|
child.cwd = test_dir_abs;
|
|
child.stdout_behavior = .Pipe;
|
|
child.stderr_behavior = .Pipe;
|
|
try child.spawn();
|
|
|
|
var stdout = std.ArrayList(u8).empty;
|
|
var stderr = std.ArrayList(u8).empty;
|
|
defer stdout.deinit(allocator);
|
|
defer stderr.deinit(allocator);
|
|
try child.collectOutput(allocator, &stdout, &stderr, 8192);
|
|
|
|
try std.testing.expect(std.mem.indexOf(u8, stderr.items, "Initializing ZX project!") != null);
|
|
}
|
|
|
|
test "init -t react" {
|
|
const zx_bin_abs = try getZxPath();
|
|
const test_dir_abs = try getTestDirPath();
|
|
defer allocator.free(zx_bin_abs);
|
|
defer allocator.free(test_dir_abs);
|
|
|
|
var child = std.process.Child.init(&.{ zx_bin_abs, "init", "react", "--template", "react" }, allocator);
|
|
child.cwd = test_dir_abs;
|
|
child.stdout_behavior = .Pipe;
|
|
child.stderr_behavior = .Pipe;
|
|
try child.spawn();
|
|
|
|
var stdout = std.ArrayList(u8).empty;
|
|
var stderr = std.ArrayList(u8).empty;
|
|
defer stdout.deinit(allocator);
|
|
defer stderr.deinit(allocator);
|
|
try child.collectOutput(allocator, &stdout, &stderr, 8192);
|
|
|
|
// std.debug.print("stderr: {s}\n", .{stderr.items});
|
|
|
|
const expected_strings = [_][]const u8{
|
|
"Initializing ZX project!",
|
|
"react",
|
|
"build.zig",
|
|
"site/main.zig",
|
|
"site/main.ts",
|
|
"site/pages/page.zx",
|
|
"site/pages/client.tsx",
|
|
"package.json",
|
|
"tsconfig.json",
|
|
};
|
|
|
|
for (expected_strings) |expected_string| {
|
|
try std.testing.expect(std.mem.indexOf(u8, stderr.items, expected_string) != null);
|
|
}
|
|
|
|
// Overwrite build.zig.zon with local zon so that the latest local zx is used
|
|
const build_zig_zon_path = try std.fs.path.join(allocator, &.{ test_dir_abs, "build.zig.zon" });
|
|
defer allocator.free(build_zig_zon_path);
|
|
var file = try std.fs.createFileAbsolute(build_zig_zon_path, .{ .truncate = true });
|
|
defer file.close();
|
|
|
|
_ = try file.writeAll(local_zon_str);
|
|
}
|
|
|
|
test "serve" {
|
|
if (!sholdRunSlowTest()) return error.SkipZigTest; // Slow test, will enable later, and execute as another steps as e2e before release
|
|
if (true) return error.Todo;
|
|
|
|
const zx_bin_abs = try getZxPath();
|
|
const test_dir_abs = try getTestDirPath();
|
|
defer allocator.free(zx_bin_abs);
|
|
defer allocator.free(test_dir_abs);
|
|
|
|
const port = "3456";
|
|
const port_colon = try std.fmt.allocPrint(allocator, ":{s}", .{port});
|
|
defer allocator.free(port_colon);
|
|
|
|
// Kill anything on that port (cross-platform)
|
|
killPort(port) catch {};
|
|
|
|
var build_child = std.process.Child.init(&.{ "zig", "build" }, allocator);
|
|
build_child.cwd = test_dir_abs;
|
|
build_child.stdout_behavior = .Ignore;
|
|
build_child.stderr_behavior = .Ignore;
|
|
try build_child.spawn();
|
|
_ = build_child.wait() catch {};
|
|
|
|
var child = std.process.Child.init(&.{ zx_bin_abs, "serve", "--port", port }, allocator);
|
|
child.cwd = test_dir_abs;
|
|
// child.stdout_behavior = .Ignore;
|
|
// child.stderr_behavior = .Ignore;
|
|
try child.spawn();
|
|
defer _ = child.kill() catch {};
|
|
errdefer _ = child.kill() catch {};
|
|
|
|
var client = std.http.Client{ .allocator = allocator };
|
|
defer client.deinit();
|
|
|
|
var aw = std.Io.Writer.Allocating.init(allocator);
|
|
defer aw.deinit();
|
|
|
|
const url = try std.fmt.allocPrint(allocator, "http://{s}:{s}", .{ "localhost", port });
|
|
defer allocator.free(url);
|
|
|
|
// wait for 2 seconds
|
|
std.Thread.sleep(std.time.ns_per_s * 1);
|
|
const result = try client.fetch(.{
|
|
.method = .GET,
|
|
.location = .{ .url = url },
|
|
.headers = std.http.Client.Request.Headers{},
|
|
.response_writer = &aw.writer,
|
|
});
|
|
|
|
// Wait 500ms
|
|
std.Thread.sleep(std.time.ns_per_ms * 500);
|
|
_ = child.kill() catch {};
|
|
errdefer _ = child.kill() catch {};
|
|
|
|
try std.testing.expectEqual(result.status, std.http.Status.ok);
|
|
}
|
|
|
|
test "init → build" {
|
|
if (!sholdRunSlowTest()) return error.SkipZigTest; // Slow test, will enable later, and execute as another steps as e2e before release
|
|
|
|
const test_dir_abs = try getTestDirPath();
|
|
defer allocator.free(test_dir_abs);
|
|
|
|
var build_child = std.process.Child.init(&.{ "zig", "build" }, allocator);
|
|
build_child.cwd = test_dir_abs;
|
|
// build_child.stdout_behavior = .Ignore;
|
|
// build_child.stderr_behavior = .Ignore;
|
|
try build_child.spawn();
|
|
const exit_code = try build_child.wait();
|
|
switch (exit_code) {
|
|
.Exited => |code| try std.testing.expectEqual(code, 0),
|
|
else => try std.testing.expect(false),
|
|
}
|
|
}
|
|
|
|
test "export" {
|
|
if (builtin.os.tag == .windows or !sholdRunSlowTest()) return error.SkipZigTest; // Export doesn't work on Windows yet
|
|
const test_dir_abs = try getTestDirPath();
|
|
const zx_bin_abs = try getZxPath();
|
|
defer allocator.free(test_dir_abs);
|
|
defer allocator.free(zx_bin_abs);
|
|
|
|
var export_child = std.process.Child.init(&.{ zx_bin_abs, "export" }, allocator);
|
|
export_child.cwd = test_dir_abs;
|
|
export_child.stdout_behavior = .Ignore;
|
|
export_child.stderr_behavior = .Ignore;
|
|
try export_child.spawn();
|
|
const exit_code = try export_child.wait();
|
|
switch (exit_code) {
|
|
.Exited => |code| try std.testing.expectEqual(code, 0),
|
|
else => try std.testing.expect(false),
|
|
}
|
|
|
|
const dist_dir_abs = try std.fs.path.join(allocator, &.{ test_dir_abs, "dist" });
|
|
defer allocator.free(dist_dir_abs);
|
|
|
|
var dist_dir = try std.fs.openDirAbsolute(dist_dir_abs, .{});
|
|
defer dist_dir.close();
|
|
|
|
const expected_files = [_][]const u8{
|
|
"index.html",
|
|
"about.html",
|
|
"assets" ++ std.fs.path.sep_str ++ "style.css",
|
|
"favicon.ico",
|
|
};
|
|
|
|
for (expected_files) |expected_file| {
|
|
const file_stat = try dist_dir.statFile(expected_file);
|
|
try std.testing.expectEqual(file_stat.kind, .file);
|
|
}
|
|
}
|
|
|
|
test "fmt" {
|
|
const zx_bin_abs = try getZxPath();
|
|
const test_dir_abs = try getTestDirPath();
|
|
defer allocator.free(zx_bin_abs);
|
|
defer allocator.free(test_dir_abs);
|
|
|
|
var child = std.process.Child.init(&.{ zx_bin_abs, "fmt", "site" ++ std.fs.path.sep_str ++ "pages" }, allocator);
|
|
child.cwd = test_dir_abs;
|
|
child.stdout_behavior = .Pipe;
|
|
child.stderr_behavior = .Pipe;
|
|
try child.spawn();
|
|
|
|
var stdout = std.ArrayList(u8).empty;
|
|
var stderr = std.ArrayList(u8).empty;
|
|
defer stdout.deinit(allocator);
|
|
defer stderr.deinit(allocator);
|
|
try child.collectOutput(allocator, &stdout, &stderr, 8192);
|
|
|
|
// std.debug.print("stderr: {s}\n", .{stderr.items});
|
|
|
|
const expected_strings = [_][]const u8{
|
|
"site" ++ std.fs.path.sep_str ++ "pages" ++ std.fs.path.sep_str ++ "layout.zx",
|
|
"site" ++ std.fs.path.sep_str ++ "pages" ++ std.fs.path.sep_str ++ "page.zx",
|
|
};
|
|
|
|
for (expected_strings) |expected_string| {
|
|
try std.testing.expect(std.mem.indexOf(u8, stdout.items, expected_string) != null);
|
|
}
|
|
try std.testing.expectEqual(stderr.items.len, 0);
|
|
}
|
|
|
|
const local_zon_str =
|
|
\\.{
|
|
\\ .name = .zx_site,
|
|
\\ .version = "0.0.0",
|
|
\\ .fingerprint = 0xc04151551dc3c31d,
|
|
\\ .minimum_zig_version = "0.15.2",
|
|
\\ .dependencies = .{
|
|
\\ .zx = .{
|
|
\\ .path = "../../",
|
|
\\ },
|
|
\\ },
|
|
\\ .paths = .{
|
|
\\ "build.zig",
|
|
\\ "build.zig.zon",
|
|
\\ "src",
|
|
\\ },
|
|
\\}
|
|
;
|
|
|
|
test "tests:beforeAll" {
|
|
std.fs.cwd().deleteTree("test/tmp") catch {};
|
|
}
|
|
|
|
test "tests:afterAll" {
|
|
// std.fs.cwd().deleteTree("test/tmp") catch {};
|
|
}
|
|
|
|
fn sholdRunSlowTest() bool {
|
|
// E2E environment variable is set
|
|
const slow_tests = std.process.getEnvVarOwned(allocator, "E2E") catch {
|
|
return false;
|
|
};
|
|
|
|
defer allocator.free(slow_tests);
|
|
return true;
|
|
}
|
|
|
|
fn getZxPath() ![]const u8 {
|
|
const zx_bin_rel = if (builtin.os.tag == .windows) "zig-out/bin/zx.exe" else "zig-out/bin/zx";
|
|
const zx_bin_abs = try std.fs.cwd().realpathAlloc(allocator, zx_bin_rel);
|
|
return zx_bin_abs;
|
|
}
|
|
|
|
fn getTestDirPath() ![]const u8 {
|
|
const test_dir = "test/tmp";
|
|
const test_dir_abs = try std.fs.cwd().realpathAlloc(allocator, test_dir);
|
|
return test_dir_abs;
|
|
}
|
|
|
|
fn killPort(port: []const u8) !void {
|
|
const target_os = builtin.target.os.tag;
|
|
|
|
if (target_os == .windows) {
|
|
// Windows: Use PowerShell to find and kill process on port
|
|
const ps_command = try std.fmt.allocPrint(
|
|
allocator,
|
|
"Get-NetTCPConnection -LocalPort {s} -ErrorAction SilentlyContinue | ForEach-Object {{ Stop-Process -Id $_.OwningProcess -Force }}",
|
|
.{port},
|
|
);
|
|
defer allocator.free(ps_command);
|
|
|
|
var kill_child = std.process.Child.init(&.{ "powershell", "-Command", ps_command }, allocator);
|
|
kill_child.stdout_behavior = .Pipe;
|
|
kill_child.stderr_behavior = .Pipe;
|
|
_ = kill_child.spawn() catch return;
|
|
_ = kill_child.wait() catch {};
|
|
} else {
|
|
// Unix-like: Use lsof and kill
|
|
const kill_command = try std.fmt.allocPrint(allocator, "kill -9 $(lsof -t -i:{s})", .{port});
|
|
defer allocator.free(kill_command);
|
|
|
|
var kill_child = std.process.Child.init(&.{ "sh", "-c", kill_command }, allocator);
|
|
kill_child.stdout_behavior = .Pipe;
|
|
kill_child.stderr_behavior = .Pipe;
|
|
_ = kill_child.spawn() catch return;
|
|
_ = kill_child.wait() catch {};
|
|
}
|
|
}
|
|
|
|
const allocator = std.testing.allocator;
|
|
|
|
const std = @import("std");
|
|
const builtin = @import("builtin");
|