mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 15:13:28 +00:00
Merge pull request #409 from karlseguin/unittest_build
Add a new unittest build step
This commit is contained in:
7
Makefile
7
Makefile
@@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
ZIG := zig
|
ZIG := zig
|
||||||
BC := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
|
BC := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
|
||||||
|
# option test filter make unittest F="server"
|
||||||
|
F=
|
||||||
|
|
||||||
# OS and ARCH
|
# OS and ARCH
|
||||||
kernel = $(shell uname -ms)
|
kernel = $(shell uname -ms)
|
||||||
@@ -42,7 +44,7 @@ help:
|
|||||||
|
|
||||||
# $(ZIG) commands
|
# $(ZIG) commands
|
||||||
# ------------
|
# ------------
|
||||||
.PHONY: build build-dev run run-release shell test bench download-zig wpt
|
.PHONY: build build-dev run run-release shell test bench download-zig wpt unittest
|
||||||
|
|
||||||
zig_version = $(shell grep 'recommended_zig_version = "' "vendor/zig-js-runtime/build.zig" | cut -d'"' -f2)
|
zig_version = $(shell grep 'recommended_zig_version = "' "vendor/zig-js-runtime/build.zig" | cut -d'"' -f2)
|
||||||
|
|
||||||
@@ -91,6 +93,9 @@ test:
|
|||||||
@$(ZIG) build test -Dengine=v8 || (printf "\e[33mTest ERROR\e[0m\n"; exit 1;)
|
@$(ZIG) build test -Dengine=v8 || (printf "\e[33mTest ERROR\e[0m\n"; exit 1;)
|
||||||
@printf "\e[33mTest OK\e[0m\n"
|
@printf "\e[33mTest OK\e[0m\n"
|
||||||
|
|
||||||
|
unittest:
|
||||||
|
@TEST_FILTER='${F}' $(ZIG) build unittest -freference-trace --summary all
|
||||||
|
|
||||||
# Install and build required dependencies commands
|
# Install and build required dependencies commands
|
||||||
# ------------
|
# ------------
|
||||||
.PHONY: install-submodule
|
.PHONY: install-submodule
|
||||||
|
|||||||
25
build.zig
25
build.zig
@@ -98,8 +98,8 @@ pub fn build(b: *std.Build) !void {
|
|||||||
|
|
||||||
// compile
|
// compile
|
||||||
const tests = b.addTest(.{
|
const tests = b.addTest(.{
|
||||||
.root_source_file = b.path("src/run_tests.zig"),
|
.root_source_file = b.path("src/main_tests.zig"),
|
||||||
.test_runner = b.path("src/test_runner.zig"),
|
.test_runner = b.path("src/main_tests.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = mode,
|
.optimize = mode,
|
||||||
});
|
});
|
||||||
@@ -119,6 +119,27 @@ pub fn build(b: *std.Build) !void {
|
|||||||
const test_step = b.step("test", "Run unit tests");
|
const test_step = b.step("test", "Run unit tests");
|
||||||
test_step.dependOn(&run_tests.step);
|
test_step.dependOn(&run_tests.step);
|
||||||
|
|
||||||
|
// unittest
|
||||||
|
// ----
|
||||||
|
|
||||||
|
// compile
|
||||||
|
const unit_tests = b.addTest(.{
|
||||||
|
.root_source_file = b.path("src/unit_tests.zig"),
|
||||||
|
.test_runner = b.path("src/unit_tests.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = mode,
|
||||||
|
});
|
||||||
|
try common(b, unit_tests, options);
|
||||||
|
|
||||||
|
const run_unit_tests = b.addRunArtifact(unit_tests);
|
||||||
|
if (b.args) |args| {
|
||||||
|
run_unit_tests.addArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// step
|
||||||
|
const unit_test_step = b.step("unittest", "Run unit tests");
|
||||||
|
unit_test_step.dependOn(&run_unit_tests.step);
|
||||||
|
|
||||||
// wpt
|
// wpt
|
||||||
// -----
|
// -----
|
||||||
|
|
||||||
|
|||||||
@@ -79,13 +79,19 @@ pub const Loader = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
test "basic url get" {
|
test "loader: get" {
|
||||||
const alloc = std.testing.allocator;
|
const alloc = std.testing.allocator;
|
||||||
var loader = Loader.init(alloc);
|
var loader = Loader.init(alloc);
|
||||||
defer loader.deinit();
|
defer loader.deinit();
|
||||||
|
|
||||||
var result = try loader.get(alloc, "https://en.wikipedia.org/wiki/Main_Page");
|
const uri = try std.Uri.parse("http://localhost:9582/loader");
|
||||||
|
var result = try loader.get(alloc, uri);
|
||||||
defer result.deinit();
|
defer result.deinit();
|
||||||
|
|
||||||
try std.testing.expect(result.req.response.status == std.http.Status.ok);
|
try std.testing.expectEqual(.ok, result.req.response.status);
|
||||||
|
|
||||||
|
var res: [128]u8 = undefined;
|
||||||
|
const size = try result.req.readAll(&res);
|
||||||
|
try std.testing.expectEqual(6, size);
|
||||||
|
try std.testing.expectEqualStrings("Hello!", res[0..6]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,19 +15,39 @@ pub const U32Iterator = struct {
|
|||||||
done: bool,
|
done: bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn _next(self: *U32Iterator) !Return {
|
pub fn _next(self: *U32Iterator) Return {
|
||||||
const i = self.index;
|
const i = self.index;
|
||||||
if (i >= self.length) {
|
if (i >= self.length) {
|
||||||
return Return{
|
return .{
|
||||||
.value = 0,
|
.value = 0,
|
||||||
.done = true,
|
.done = true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
self.index += 1;
|
self.index = i + 1;
|
||||||
return Return{
|
return .{
|
||||||
.value = i,
|
.value = i,
|
||||||
.done = false,
|
.done = false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const testing = std.testing;
|
||||||
|
test "U32Iterator" {
|
||||||
|
const Return = U32Iterator.Return;
|
||||||
|
|
||||||
|
{
|
||||||
|
var it = U32Iterator{ .length = 0 };
|
||||||
|
try testing.expectEqual(Return{ .value = 0, .done = true }, it._next());
|
||||||
|
try testing.expectEqual(Return{ .value = 0, .done = true }, it._next());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
var it = U32Iterator{ .length = 3 };
|
||||||
|
try testing.expectEqual(Return{ .value = 0, .done = false }, it._next());
|
||||||
|
try testing.expectEqual(Return{ .value = 1, .done = false }, it._next());
|
||||||
|
try testing.expectEqual(Return{ .value = 2, .done = false }, it._next());
|
||||||
|
try testing.expectEqual(Return{ .value = 0, .done = true }, it._next());
|
||||||
|
try testing.expectEqual(Return{ .value = 0, .done = true }, it._next());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -223,8 +223,14 @@ pub fn main() !void {
|
|||||||
try parser.init();
|
try parser.init();
|
||||||
defer parser.deinit();
|
defer parser.deinit();
|
||||||
|
|
||||||
|
std.testing.allocator_instance = .{};
|
||||||
try test_fn.func();
|
try test_fn.func();
|
||||||
std.debug.print("{s}\tOK\n", .{test_fn.name});
|
|
||||||
|
if (std.testing.allocator_instance.deinit() == .leak) {
|
||||||
|
std.debug.print("======Memory Leak: {s}======\n", .{test_fn.name});
|
||||||
|
} else {
|
||||||
|
std.debug.print("{s}\tOK\n", .{test_fn.name});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,20 +149,22 @@ pub const Bottle = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn _setItem(self: *Bottle, k: []const u8, v: []const u8) !void {
|
pub fn _setItem(self: *Bottle, k: []const u8, v: []const u8) !void {
|
||||||
const old = self.map.get(k);
|
const gop = self.map.getOrPut(self.alloc, k) catch |e| {
|
||||||
if (old != null and std.mem.eql(u8, v, old.?)) return;
|
|
||||||
|
|
||||||
// owns k and v by copying them.
|
|
||||||
const kk = try self.alloc.dupe(u8, k);
|
|
||||||
errdefer self.alloc.free(kk);
|
|
||||||
const vv = try self.alloc.dupe(u8, v);
|
|
||||||
errdefer self.alloc.free(vv);
|
|
||||||
|
|
||||||
self.map.put(self.alloc, kk, vv) catch |e| {
|
|
||||||
log.debug("set item: {any}", .{e});
|
log.debug("set item: {any}", .{e});
|
||||||
return DOMError.QuotaExceeded;
|
return DOMError.QuotaExceeded;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (gop.found_existing == false) {
|
||||||
|
gop.key_ptr.* = try self.alloc.dupe(u8, k);
|
||||||
|
gop.value_ptr.* = try self.alloc.dupe(u8, v);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std.mem.eql(u8, v, gop.value_ptr.*) == false) {
|
||||||
|
self.alloc.free(gop.value_ptr.*);
|
||||||
|
gop.value_ptr.* = try self.alloc.dupe(u8, v);
|
||||||
|
}
|
||||||
|
|
||||||
// > Broadcast this with key, oldValue, and value.
|
// > Broadcast this with key, oldValue, and value.
|
||||||
// https://html.spec.whatwg.org/multipage/webstorage.html#the-storageevent-interface
|
// https://html.spec.whatwg.org/multipage/webstorage.html#the-storageevent-interface
|
||||||
//
|
//
|
||||||
@@ -175,8 +177,10 @@ pub const Bottle = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn _removeItem(self: *Bottle, k: []const u8) !void {
|
pub fn _removeItem(self: *Bottle, k: []const u8) !void {
|
||||||
const old = self.map.fetchRemove(k);
|
if (self.map.fetchRemove(k)) |kv| {
|
||||||
if (old == null) return;
|
self.alloc.free(kv.key);
|
||||||
|
self.alloc.free(kv.value);
|
||||||
|
}
|
||||||
|
|
||||||
// > Broadcast this with key, oldValue, and null.
|
// > Broadcast this with key, oldValue, and null.
|
||||||
// https://html.spec.whatwg.org/multipage/webstorage.html#the-storageevent-interface
|
// https://html.spec.whatwg.org/multipage/webstorage.html#the-storageevent-interface
|
||||||
@@ -235,14 +239,17 @@ test "storage bottle" {
|
|||||||
var bottle = Bottle.init(std.testing.allocator);
|
var bottle = Bottle.init(std.testing.allocator);
|
||||||
defer bottle.deinit();
|
defer bottle.deinit();
|
||||||
|
|
||||||
try std.testing.expect(0 == bottle.get_length());
|
try std.testing.expectEqual(0, bottle.get_length());
|
||||||
try std.testing.expect(null == bottle._getItem("foo"));
|
try std.testing.expectEqual(null, bottle._getItem("foo"));
|
||||||
|
|
||||||
try bottle._setItem("foo", "bar");
|
try bottle._setItem("foo", "bar");
|
||||||
try std.testing.expect(std.mem.eql(u8, "bar", bottle._getItem("foo").?));
|
try std.testing.expectEqualStrings("bar", bottle._getItem("foo").?);
|
||||||
|
|
||||||
|
try bottle._setItem("foo", "other");
|
||||||
|
try std.testing.expectEqualStrings("other", bottle._getItem("foo").?);
|
||||||
|
|
||||||
try bottle._removeItem("foo");
|
try bottle._removeItem("foo");
|
||||||
|
|
||||||
try std.testing.expect(0 == bottle.get_length());
|
try std.testing.expectEqual(0, bottle.get_length());
|
||||||
try std.testing.expect(null == bottle._getItem("foo"));
|
try std.testing.expectEqual(null, bottle._getItem("foo"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
// Copyright (C) 2023-2024 Lightpanda (Selecy SAS)
|
|
||||||
//
|
|
||||||
// Francis Bouvier <francis@lightpanda.io>
|
|
||||||
// Pierre Tachoire <pierre@lightpanda.io>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Affero General Public License as
|
|
||||||
// published by the Free Software Foundation, either version 3 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Affero General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
const std = @import("std");
|
|
||||||
|
|
||||||
const tests = @import("run_tests.zig");
|
|
||||||
|
|
||||||
pub const Types = tests.Types;
|
|
||||||
pub const UserContext = tests.UserContext;
|
|
||||||
pub const IO = tests.IO;
|
|
||||||
|
|
||||||
pub fn main() !void {
|
|
||||||
try tests.main();
|
|
||||||
}
|
|
||||||
347
src/unit_tests.zig
Normal file
347
src/unit_tests.zig
Normal file
@@ -0,0 +1,347 @@
|
|||||||
|
// Copyright (C) 2023-2024 Lightpanda (Selecy SAS)
|
||||||
|
//
|
||||||
|
// Francis Bouvier <francis@lightpanda.io>
|
||||||
|
// Pierre Tachoire <pierre@lightpanda.io>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
pub const std_options = std.Options{
|
||||||
|
.http_disable_tls = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const BORDER = "=" ** 80;
|
||||||
|
|
||||||
|
// use in custom panic handler
|
||||||
|
var current_test: ?[]const u8 = null;
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
var mem: [8192]u8 = undefined;
|
||||||
|
var fba = std.heap.FixedBufferAllocator.init(&mem);
|
||||||
|
|
||||||
|
const allocator = fba.allocator();
|
||||||
|
|
||||||
|
const env = Env.init(allocator);
|
||||||
|
defer env.deinit(allocator);
|
||||||
|
|
||||||
|
var slowest = SlowTracker.init(allocator, 5);
|
||||||
|
defer slowest.deinit();
|
||||||
|
|
||||||
|
var pass: usize = 0;
|
||||||
|
var fail: usize = 0;
|
||||||
|
var skip: usize = 0;
|
||||||
|
var leak: usize = 0;
|
||||||
|
|
||||||
|
const address = try std.net.Address.parseIp("127.0.0.1", 9582);
|
||||||
|
var listener = try address.listen(.{ .reuse_address = true });
|
||||||
|
defer listener.deinit();
|
||||||
|
const http_thread = try std.Thread.spawn(.{}, serverHTTP, .{&listener});
|
||||||
|
defer http_thread.join();
|
||||||
|
|
||||||
|
const printer = Printer.init();
|
||||||
|
printer.fmt("\r\x1b[0K", .{}); // beginning of line and clear to end of line
|
||||||
|
|
||||||
|
for (builtin.test_functions) |t| {
|
||||||
|
if (std.mem.eql(u8, t.name, "unit_tests.test_0")) {
|
||||||
|
// don't display anything for this test
|
||||||
|
try t.func();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var status = Status.pass;
|
||||||
|
slowest.startTiming();
|
||||||
|
|
||||||
|
const is_unnamed_test = isUnnamed(t);
|
||||||
|
if (env.filter) |f| {
|
||||||
|
if (!is_unnamed_test and std.mem.indexOf(u8, t.name, f) == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const friendly_name = blk: {
|
||||||
|
const name = t.name;
|
||||||
|
var it = std.mem.splitScalar(u8, name, '.');
|
||||||
|
while (it.next()) |value| {
|
||||||
|
if (std.mem.eql(u8, value, "test")) {
|
||||||
|
const rest = it.rest();
|
||||||
|
break :blk if (rest.len > 0) rest else name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break :blk name;
|
||||||
|
};
|
||||||
|
|
||||||
|
current_test = friendly_name;
|
||||||
|
std.testing.allocator_instance = .{};
|
||||||
|
const result = t.func();
|
||||||
|
current_test = null;
|
||||||
|
|
||||||
|
const ns_taken = slowest.endTiming(friendly_name);
|
||||||
|
|
||||||
|
if (std.testing.allocator_instance.deinit() == .leak) {
|
||||||
|
leak += 1;
|
||||||
|
printer.status(.fail, "\n{s}\n\"{s}\" - Memory Leak\n{s}\n", .{ BORDER, friendly_name, BORDER });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result) |_| {
|
||||||
|
pass += 1;
|
||||||
|
} else |err| switch (err) {
|
||||||
|
error.SkipZigTest => {
|
||||||
|
skip += 1;
|
||||||
|
status = .skip;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
status = .fail;
|
||||||
|
fail += 1;
|
||||||
|
printer.status(.fail, "\n{s}\n\"{s}\" - {s}\n{s}\n", .{ BORDER, friendly_name, @errorName(err), BORDER });
|
||||||
|
if (@errorReturnTrace()) |trace| {
|
||||||
|
std.debug.dumpStackTrace(trace.*);
|
||||||
|
}
|
||||||
|
if (env.fail_first) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env.verbose) {
|
||||||
|
const ms = @as(f64, @floatFromInt(ns_taken)) / 1_000_000.0;
|
||||||
|
printer.status(status, "{s} ({d:.2}ms)\n", .{ friendly_name, ms });
|
||||||
|
} else {
|
||||||
|
printer.status(status, ".", .{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const total_tests = pass + fail;
|
||||||
|
const status = if (fail == 0) Status.pass else Status.fail;
|
||||||
|
printer.status(status, "\n{d} of {d} test{s} passed\n", .{ pass, total_tests, if (total_tests != 1) "s" else "" });
|
||||||
|
if (skip > 0) {
|
||||||
|
printer.status(.skip, "{d} test{s} skipped\n", .{ skip, if (skip != 1) "s" else "" });
|
||||||
|
}
|
||||||
|
if (leak > 0) {
|
||||||
|
printer.status(.fail, "{d} test{s} leaked\n", .{ leak, if (leak != 1) "s" else "" });
|
||||||
|
}
|
||||||
|
printer.fmt("\n", .{});
|
||||||
|
try slowest.display(printer);
|
||||||
|
printer.fmt("\n", .{});
|
||||||
|
std.posix.exit(if (fail == 0) 0 else 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Printer = struct {
|
||||||
|
out: std.fs.File.Writer,
|
||||||
|
|
||||||
|
fn init() Printer {
|
||||||
|
return .{
|
||||||
|
.out = std.io.getStdErr().writer(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fmt(self: Printer, comptime format: []const u8, args: anytype) void {
|
||||||
|
std.fmt.format(self.out, format, args) catch unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn status(self: Printer, s: Status, comptime format: []const u8, args: anytype) void {
|
||||||
|
const color = switch (s) {
|
||||||
|
.pass => "\x1b[32m",
|
||||||
|
.fail => "\x1b[31m",
|
||||||
|
.skip => "\x1b[33m",
|
||||||
|
else => "",
|
||||||
|
};
|
||||||
|
const out = self.out;
|
||||||
|
out.writeAll(color) catch @panic("writeAll failed?!");
|
||||||
|
std.fmt.format(out, format, args) catch @panic("std.fmt.format failed?!");
|
||||||
|
self.fmt("\x1b[0m", .{});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Status = enum {
|
||||||
|
pass,
|
||||||
|
fail,
|
||||||
|
skip,
|
||||||
|
text,
|
||||||
|
};
|
||||||
|
|
||||||
|
const SlowTracker = struct {
|
||||||
|
const SlowestQueue = std.PriorityDequeue(TestInfo, void, compareTiming);
|
||||||
|
max: usize,
|
||||||
|
slowest: SlowestQueue,
|
||||||
|
timer: std.time.Timer,
|
||||||
|
|
||||||
|
fn init(allocator: Allocator, count: u32) SlowTracker {
|
||||||
|
const timer = std.time.Timer.start() catch @panic("failed to start timer");
|
||||||
|
var slowest = SlowestQueue.init(allocator, {});
|
||||||
|
slowest.ensureTotalCapacity(count) catch @panic("OOM");
|
||||||
|
return .{
|
||||||
|
.max = count,
|
||||||
|
.timer = timer,
|
||||||
|
.slowest = slowest,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const TestInfo = struct {
|
||||||
|
ns: u64,
|
||||||
|
name: []const u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn deinit(self: SlowTracker) void {
|
||||||
|
self.slowest.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn startTiming(self: *SlowTracker) void {
|
||||||
|
self.timer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn endTiming(self: *SlowTracker, test_name: []const u8) u64 {
|
||||||
|
var timer = self.timer;
|
||||||
|
const ns = timer.lap();
|
||||||
|
|
||||||
|
var slowest = &self.slowest;
|
||||||
|
|
||||||
|
if (slowest.count() < self.max) {
|
||||||
|
// Capacity is fixed to the # of slow tests we want to track
|
||||||
|
// If we've tracked fewer tests than this capacity, than always add
|
||||||
|
slowest.add(TestInfo{ .ns = ns, .name = test_name }) catch @panic("failed to track test timing");
|
||||||
|
return ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Optimization to avoid shifting the dequeue for the common case
|
||||||
|
// where the test isn't one of our slowest.
|
||||||
|
const fastest_of_the_slow = slowest.peekMin() orelse unreachable;
|
||||||
|
if (fastest_of_the_slow.ns > ns) {
|
||||||
|
// the test was faster than our fastest slow test, don't add
|
||||||
|
return ns;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the previous fastest of our slow tests, has been pushed off.
|
||||||
|
_ = slowest.removeMin();
|
||||||
|
slowest.add(TestInfo{ .ns = ns, .name = test_name }) catch @panic("failed to track test timing");
|
||||||
|
return ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display(self: *SlowTracker, printer: Printer) !void {
|
||||||
|
var slowest = self.slowest;
|
||||||
|
const count = slowest.count();
|
||||||
|
printer.fmt("Slowest {d} test{s}: \n", .{ count, if (count != 1) "s" else "" });
|
||||||
|
while (slowest.removeMinOrNull()) |info| {
|
||||||
|
const ms = @as(f64, @floatFromInt(info.ns)) / 1_000_000.0;
|
||||||
|
printer.fmt(" {d:.2}ms\t{s}\n", .{ ms, info.name });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compareTiming(context: void, a: TestInfo, b: TestInfo) std.math.Order {
|
||||||
|
_ = context;
|
||||||
|
return std.math.order(a.ns, b.ns);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Env = struct {
|
||||||
|
verbose: bool,
|
||||||
|
fail_first: bool,
|
||||||
|
filter: ?[]const u8,
|
||||||
|
|
||||||
|
fn init(allocator: Allocator) Env {
|
||||||
|
return .{
|
||||||
|
.verbose = readEnvBool(allocator, "TEST_VERBOSE", true),
|
||||||
|
.fail_first = readEnvBool(allocator, "TEST_FAIL_FIRST", false),
|
||||||
|
.filter = readEnv(allocator, "TEST_FILTER"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deinit(self: Env, allocator: Allocator) void {
|
||||||
|
if (self.filter) |f| {
|
||||||
|
allocator.free(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readEnv(allocator: Allocator, key: []const u8) ?[]const u8 {
|
||||||
|
const v = std.process.getEnvVarOwned(allocator, key) catch |err| {
|
||||||
|
if (err == error.EnvironmentVariableNotFound) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
std.log.warn("failed to get env var {s} due to err {}", .{ key, err });
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readEnvBool(allocator: Allocator, key: []const u8, deflt: bool) bool {
|
||||||
|
const value = readEnv(allocator, key) orelse return deflt;
|
||||||
|
defer allocator.free(value);
|
||||||
|
return std.ascii.eqlIgnoreCase(value, "true");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fn isUnnamed(t: std.builtin.TestFn) bool {
|
||||||
|
const marker = ".test_";
|
||||||
|
const test_name = t.name;
|
||||||
|
const index = std.mem.indexOf(u8, test_name, marker) orelse return false;
|
||||||
|
_ = std.fmt.parseInt(u32, test_name[index + marker.len ..], 10) catch return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serverHTTP(listener: *std.net.Server) !void {
|
||||||
|
var read_buffer: [1024]u8 = undefined;
|
||||||
|
ACCEPT: while (true) {
|
||||||
|
var conn = try listener.accept();
|
||||||
|
defer conn.stream.close();
|
||||||
|
var server = std.http.Server.init(conn, &read_buffer);
|
||||||
|
|
||||||
|
while (server.state == .ready) {
|
||||||
|
var request = server.receiveHead() catch |err| switch (err) {
|
||||||
|
error.HttpConnectionClosing => continue :ACCEPT,
|
||||||
|
else => {
|
||||||
|
std.debug.print("Test HTTP Server error: {}\n", .{err});
|
||||||
|
return err;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const path = request.head.target;
|
||||||
|
if (std.mem.eql(u8, path, "/loader")) {
|
||||||
|
try writeResponse(&request, .{
|
||||||
|
.body = "Hello!",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Response = struct {
|
||||||
|
body: []const u8 = "",
|
||||||
|
status: std.http.Status = .ok,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn writeResponse(req: *std.http.Server.Request, res: Response) !void {
|
||||||
|
try req.respond(res.body, .{ .status = res.status });
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
std.testing.refAllDecls(@import("url/query.zig"));
|
||||||
|
std.testing.refAllDecls(@import("browser/dump.zig"));
|
||||||
|
std.testing.refAllDecls(@import("browser/loader.zig"));
|
||||||
|
std.testing.refAllDecls(@import("browser/mime.zig"));
|
||||||
|
std.testing.refAllDecls(@import("cdp/msg.zig"));
|
||||||
|
std.testing.refAllDecls(@import("css/css.zig"));
|
||||||
|
std.testing.refAllDecls(@import("css/libdom_test.zig"));
|
||||||
|
std.testing.refAllDecls(@import("css/match_test.zig"));
|
||||||
|
std.testing.refAllDecls(@import("css/parser.zig"));
|
||||||
|
std.testing.refAllDecls(@import("generate.zig"));
|
||||||
|
std.testing.refAllDecls(@import("http/Client.zig"));
|
||||||
|
std.testing.refAllDecls(@import("msg.zig"));
|
||||||
|
std.testing.refAllDecls(@import("storage/storage.zig"));
|
||||||
|
std.testing.refAllDecls(@import("iterator/iterator.zig"));
|
||||||
|
}
|
||||||
@@ -62,6 +62,7 @@ pub const Values = struct {
|
|||||||
// append by taking the ownership of the key and the value
|
// append by taking the ownership of the key and the value
|
||||||
fn appendOwned(self: *Values, k: []const u8, v: []const u8) !void {
|
fn appendOwned(self: *Values, k: []const u8, v: []const u8) !void {
|
||||||
if (self.map.getPtr(k)) |list| {
|
if (self.map.getPtr(k)) |list| {
|
||||||
|
self.alloc.free(k);
|
||||||
return try list.append(self.alloc, v);
|
return try list.append(self.alloc, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user