mirror of
https://github.com/ziex-dev/ziex.git
synced 2026-07-21 02:59:36 -06:00
492 lines
16 KiB
Zig
492 lines
16 KiB
Zig
test "init" {
|
|
if (!test_util.shouldRunSlowTest()) return error.SkipZigTest;
|
|
try test_cmd(.{
|
|
.args = &.{"init"},
|
|
.expected_exit_code = 0,
|
|
.expected_stderr_strings = &.{
|
|
"Initializing ZX project!",
|
|
"main.zig",
|
|
".gitattributes",
|
|
"client.zx",
|
|
"page.zx",
|
|
},
|
|
.expected_files = &.{
|
|
"build.zig.zon",
|
|
"build.zig",
|
|
"app/main.zig",
|
|
"app/pages/page.zx",
|
|
"app/pages/client.zx",
|
|
"app/assets/style.css",
|
|
"app/public/favicon.ico",
|
|
".gitignore",
|
|
".gitattributes",
|
|
"README.md",
|
|
},
|
|
});
|
|
}
|
|
|
|
test "init → init" {
|
|
if (!test_util.shouldRunSlowTest()) return error.SkipZigTest;
|
|
try test_cmd(.{
|
|
.args = &.{"init"},
|
|
.expected_exit_code = 0,
|
|
.expected_stderr_strings = &.{
|
|
"Directory is not empty",
|
|
},
|
|
});
|
|
}
|
|
|
|
test "init --force" {
|
|
if (!test_util.shouldRunSlowTest()) return error.SkipZigTest;
|
|
try test_cmd(.{
|
|
.args = &.{ "init", "--force" },
|
|
.expected_exit_code = 0,
|
|
.expected_stderr_strings = &.{
|
|
"Initializing ZX project!",
|
|
"main.zig",
|
|
"page.zx",
|
|
},
|
|
.expected_files = &.{
|
|
"build.zig.zon",
|
|
"build.zig",
|
|
"app/main.zig",
|
|
"app/pages/page.zx",
|
|
"app/pages/client.zx",
|
|
".gitignore",
|
|
".gitattributes",
|
|
"README.md",
|
|
},
|
|
});
|
|
}
|
|
|
|
test "init -t react" {
|
|
if (!test_util.shouldRunSlowTest()) return error.SkipZigTest;
|
|
try test_cmd(.{
|
|
.args = &.{ "init", "react", "--template", "react" },
|
|
.expected_exit_code = 0,
|
|
.expected_stderr_strings = &.{
|
|
"Initializing ZX project!",
|
|
"react",
|
|
"build.zig",
|
|
"main.zig",
|
|
"main.ts",
|
|
"page.zx",
|
|
"client.tsx",
|
|
"package.json",
|
|
".gitattributes",
|
|
"tsconfig.json",
|
|
},
|
|
.expected_files = &.{
|
|
"react/build.zig.zon",
|
|
"react/build.zig",
|
|
"react/app/main.zig",
|
|
"react/app/main.ts",
|
|
"react/app/pages/page.zx",
|
|
"react/app/pages/client.tsx",
|
|
"react/package.json",
|
|
"react/.gitattributes",
|
|
"react/tsconfig.json",
|
|
},
|
|
});
|
|
}
|
|
|
|
// 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 (!test_util.shouldRunSlowTest()) return error.SkipZigTest;
|
|
|
|
const test_dir_abs = try getTestDirPath();
|
|
defer allocator.free(test_dir_abs);
|
|
|
|
// Update build.zig.zon to use the local zx dependency, copy local_zon_str to build.zig.zon
|
|
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 build_zig_zon = try std.fs.openDirAbsolute(test_dir_abs, .{});
|
|
defer build_zig_zon.close();
|
|
try build_zig_zon.writeFile(.{ .sub_path = build_zig_zon_path, .data = local_zon_str });
|
|
|
|
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 "init → build -t react" {
|
|
if (!test_util.shouldRunSlowTest()) return error.SkipZigTest;
|
|
|
|
const test_dir_abs = try getTestDirPath();
|
|
defer allocator.free(test_dir_abs);
|
|
|
|
// Update build.zig.zon to use the local zx dependency, copy local_zon_str to build.zig.zon
|
|
const build_zig_zon_path = try std.fs.path.join(allocator, &.{ test_dir_abs, "react", "build.zig.zon" });
|
|
defer allocator.free(build_zig_zon_path);
|
|
var build_zig_zon = try std.fs.openDirAbsolute(test_dir_abs, .{});
|
|
defer build_zig_zon.close();
|
|
|
|
var aw = std.io.Writer.Allocating.init(allocator);
|
|
defer aw.deinit();
|
|
try std.zon.stringify.serialize(local_wasm_zon_str, .{ .whitespace = true }, &aw.writer);
|
|
try build_zig_zon.writeFile(.{ .sub_path = build_zig_zon_path, .data = aw.written() });
|
|
|
|
const wasm_path = try std.fs.path.join(allocator, &.{ test_dir_abs, "react" });
|
|
defer allocator.free(wasm_path);
|
|
var build_child = std.process.Child.init(&.{ "zig", "build" }, allocator);
|
|
build_child.cwd = wasm_path;
|
|
// 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 (!test_util.shouldRunSlowTest()) return error.SkipZigTest; // Export doesn't work on Windows yet
|
|
killPort("3000") catch {};
|
|
try test_cmd(.{
|
|
.args = &.{"export"},
|
|
.expected_exit_code = 0,
|
|
.expected_stderr_strings = &.{
|
|
"Building static ZX site!",
|
|
"dist",
|
|
"index.html",
|
|
"about.html",
|
|
"assets" ++ std.fs.path.sep_str ++ "style.css",
|
|
"favicon.ico",
|
|
},
|
|
.expected_files = &.{
|
|
"dist/index.html",
|
|
"dist/about.html",
|
|
"dist/assets/style.css",
|
|
"dist/favicon.ico",
|
|
},
|
|
});
|
|
}
|
|
|
|
test "bundle" {
|
|
if (!test_util.shouldRunSlowTest()) return error.SkipZigTest;
|
|
try test_cmd(.{
|
|
.args = &.{"bundle"},
|
|
.expected_exit_code = 0,
|
|
.expected_stderr_strings = &.{
|
|
"Bundling ZX site!",
|
|
"bundle",
|
|
"ziex_app",
|
|
"style.css",
|
|
"favicon.ico",
|
|
},
|
|
.expected_files = &.{
|
|
"bundle/ziex_app" ++ (if (builtin.os.tag == .windows) ".exe" else ""),
|
|
"bundle/static/assets/style.css",
|
|
"bundle/static/favicon.ico",
|
|
},
|
|
});
|
|
}
|
|
|
|
test "bundle --docker" {
|
|
if (!test_util.shouldRunSlowTest()) return error.SkipZigTest;
|
|
try test_cmd(.{
|
|
.args = &.{ "bundle", "--docker" },
|
|
.expected_exit_code = 0,
|
|
.expected_stderr_strings = &.{
|
|
"Bundling ZX site!",
|
|
"bundle",
|
|
"Dockerfile",
|
|
".dockerignore",
|
|
},
|
|
.expected_files = &.{
|
|
"Dockerfile",
|
|
".dockerignore",
|
|
},
|
|
});
|
|
}
|
|
|
|
test "bundle --docker-compose" {
|
|
if (!test_util.shouldRunSlowTest()) return error.SkipZigTest;
|
|
try test_cmd(.{
|
|
.args = &.{ "bundle", "--docker-compose" },
|
|
.expected_exit_code = 0,
|
|
.expected_stderr_strings = &.{
|
|
"Bundling ZX site!",
|
|
"bundle",
|
|
"Dockerfile",
|
|
"compose.yml",
|
|
".dockerignore",
|
|
},
|
|
.expected_files = &.{
|
|
"Dockerfile",
|
|
"compose.yml",
|
|
".dockerignore",
|
|
},
|
|
});
|
|
}
|
|
|
|
test "fmt" {
|
|
try test_cmd(.{
|
|
.args = &.{ "fmt", "app" ++ std.fs.path.sep_str ++ "pages" },
|
|
.expected_exit_code = 0,
|
|
.expected_stdout_strings = &.{
|
|
// "app" ++ std.fs.path.sep_str ++ "pages" ++ std.fs.path.sep_str ++ "layout.zx",
|
|
// "app" ++ std.fs.path.sep_str ++ "pages" ++ std.fs.path.sep_str ++ "page.zx",
|
|
},
|
|
});
|
|
}
|
|
|
|
test "upgrade" {
|
|
if (!test_util.shouldRunSlowTest()) return error.SkipZigTest;
|
|
try test_cmd(.{
|
|
.args = &.{"upgrade"},
|
|
.expected_exit_code = 0,
|
|
.expected_stdout_strings = &.{
|
|
"was installed successfully",
|
|
// "0.1.0-dev",
|
|
},
|
|
.expected_files = &.{},
|
|
// .debug = true,
|
|
});
|
|
}
|
|
|
|
const TestCmdOptions = struct {
|
|
args: []const []const u8,
|
|
expected_stderr_strings: []const []const u8 = &.{},
|
|
expected_stdout_strings: []const []const u8 = &.{},
|
|
expected_exit_code: i32 = 0,
|
|
expected_files: []const []const u8 = &.{},
|
|
debug: bool = false,
|
|
};
|
|
fn test_cmd(options: TestCmdOptions) !void {
|
|
const zx_bin_abs = try getZxPath();
|
|
const test_dir_abs = try getTestDirPath();
|
|
defer allocator.free(zx_bin_abs);
|
|
defer allocator.free(test_dir_abs);
|
|
|
|
// Delete bundle or dist directory if it exists
|
|
var test_dir = try std.fs.openDirAbsolute(test_dir_abs, .{});
|
|
defer test_dir.close();
|
|
test_dir.deleteTree("bundle") catch {};
|
|
test_dir.deleteTree("dist") catch {};
|
|
|
|
var args = std.ArrayList([]const u8).empty;
|
|
defer args.deinit(allocator);
|
|
try args.appendSlice(allocator, &.{zx_bin_abs});
|
|
try args.appendSlice(allocator, options.args);
|
|
|
|
var child = std.process.Child.init(args.items, 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);
|
|
|
|
if (options.debug) {
|
|
std.debug.print("\nstdout: {s}", .{stdout.items});
|
|
std.debug.print("\nstderr: {s}", .{stderr.items});
|
|
}
|
|
|
|
for (options.expected_stderr_strings) |expected_string| {
|
|
if (std.mem.indexOf(u8, stderr.items, expected_string) == null) {
|
|
std.debug.print("\nExpected stderr to contain: '{s}'\nActual stderr:\n{s}\n", .{ expected_string, stderr.items });
|
|
return error.TestExpectedEqual;
|
|
}
|
|
}
|
|
for (options.expected_stdout_strings) |expected_string| {
|
|
if (std.mem.indexOf(u8, stdout.items, expected_string) == null) {
|
|
std.debug.print("\nExpected stdout to contain: '{s}'\nActual stdout:\n{s}\n", .{ expected_string, stdout.items });
|
|
return error.TestExpectedEqual;
|
|
}
|
|
}
|
|
const exit_code = try child.wait();
|
|
switch (exit_code) {
|
|
.Exited => |code| {
|
|
if (code != options.expected_exit_code) {
|
|
std.debug.print("\nExpected exit code: {d}, got: {d}\nstderr:\n{s}\nstdout:\n{s}\n", .{ options.expected_exit_code, code, stderr.items, stdout.items });
|
|
return error.TestExpectedEqual;
|
|
}
|
|
},
|
|
else => {
|
|
std.debug.print("\nProcess terminated abnormally\nstderr:\n{s}\nstdout:\n{s}\n", .{ stderr.items, stdout.items });
|
|
return error.TestExpectedEqual;
|
|
},
|
|
}
|
|
|
|
for (options.expected_files) |expected_file| {
|
|
var expected_file_path = std.ArrayList([]const u8).empty;
|
|
defer expected_file_path.deinit(allocator);
|
|
try expected_file_path.appendSlice(allocator, &.{test_dir_abs});
|
|
|
|
var path_iter = std.mem.splitSequence(u8, expected_file, "/");
|
|
while (path_iter.next()) |part| {
|
|
if (part.len > 0) {
|
|
try expected_file_path.append(allocator, part);
|
|
}
|
|
}
|
|
const expected_file_path_str = try std.fs.path.join(allocator, expected_file_path.items);
|
|
defer allocator.free(expected_file_path_str);
|
|
|
|
const file_stat = try std.fs.cwd().statFile(expected_file_path_str);
|
|
try std.testing.expectEqual(file_stat.kind, .file);
|
|
}
|
|
}
|
|
|
|
const local_zon_str =
|
|
\\.{
|
|
\\ .name = .ziex_app,
|
|
\\ .version = "0.0.0",
|
|
\\ .fingerprint = 0x7246d8c908f650a4,
|
|
\\ .minimum_zig_version = "0.15.2",
|
|
\\ .dependencies = .{
|
|
\\ .zx = .{
|
|
\\ .path = "../../",
|
|
\\ },
|
|
\\ },
|
|
\\ .paths = .{
|
|
\\ "build.zig",
|
|
\\ "build.zig.zon",
|
|
\\ "app",
|
|
\\ },
|
|
\\}
|
|
;
|
|
|
|
var local_wasm_zon_str = .{
|
|
.name = .ziex_app,
|
|
.version = "0.0.0",
|
|
.fingerprint = 0x7246d8c908f650a4,
|
|
.minimum_zig_version = "0.15.2",
|
|
.dependencies = .{
|
|
.zx = .{
|
|
.path = "../../../",
|
|
},
|
|
},
|
|
.paths = .{
|
|
"build.zig",
|
|
"build.zig.zon",
|
|
"app",
|
|
},
|
|
};
|
|
|
|
test "tests:beforeAll" {
|
|
std.fs.cwd().deleteTree("test/tmp") catch {};
|
|
std.fs.cwd().makeDir("test/tmp") catch {};
|
|
}
|
|
|
|
test "tests:afterAll" {
|
|
// std.fs.cwd().deleteTree("test/tmp") catch {};
|
|
}
|
|
|
|
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 test_util = @import("./../util.zig");
|
|
|
|
const std = @import("std");
|
|
const zx = @import("zx");
|
|
const builtin = @import("builtin");
|