mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-22 12:44:43 +00:00
Simplify tests in markdown
This commit is contained in:
@@ -180,7 +180,6 @@ fn renderElement(el: *Element, state: *State, writer: *std.Io.Writer, page: *Pag
|
|||||||
.td, .th => {
|
.td, .th => {
|
||||||
// Note: leading pipe handled by previous cell closing or tr opening
|
// Note: leading pipe handled by previous cell closing or tr opening
|
||||||
state.last_char_was_newline = false;
|
state.last_char_was_newline = false;
|
||||||
// Add spacing
|
|
||||||
try writer.writeByte(' ');
|
try writer.writeByte(' ');
|
||||||
},
|
},
|
||||||
.blockquote => {
|
.blockquote => {
|
||||||
@@ -255,7 +254,7 @@ fn renderElement(el: *Element, state: *State, writer: *std.Io.Writer, page: *Pag
|
|||||||
state.last_char_was_newline = false;
|
state.last_char_was_newline = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return; // Void element
|
return;
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
@@ -370,17 +369,13 @@ fn renderText(text: []const u8, state: *State, writer: *std.Io.Writer) anyerror!
|
|||||||
var it = std.mem.tokenizeAny(u8, text, " \t\n\r");
|
var it = std.mem.tokenizeAny(u8, text, " \t\n\r");
|
||||||
var first = true;
|
var first = true;
|
||||||
while (it.next()) |word| {
|
while (it.next()) |word| {
|
||||||
// If this is the first word we're writing in this sequence...
|
|
||||||
if (first) {
|
if (first) {
|
||||||
// ...and we didn't just write a newline...
|
|
||||||
if (!state.last_char_was_newline) {
|
if (!state.last_char_was_newline) {
|
||||||
// ...check if the original text had leading whitespace.
|
|
||||||
if (text.len > 0 and std.ascii.isWhitespace(text[0])) {
|
if (text.len > 0 and std.ascii.isWhitespace(text[0])) {
|
||||||
try writer.writeByte(' ');
|
try writer.writeByte(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Between words always add space
|
|
||||||
try writer.writeByte(' ');
|
try writer.writeByte(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,27 +393,9 @@ fn renderText(text: []const u8, state: *State, writer: *std.Io.Writer) anyerror!
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn escapeMarkdown(writer: *std.Io.Writer, text: []const u8) !void {
|
fn escapeMarkdown(writer: *std.Io.Writer, text: []const u8) !void {
|
||||||
// Escaping: \ ` * _ { } [ ] ( ) # + - ! | < >
|
|
||||||
for (text) |c| {
|
for (text) |c| {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
'\\',
|
'\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '#', '+', '-', '!', '|', '<', '>' => {
|
||||||
'`',
|
|
||||||
'*',
|
|
||||||
'_',
|
|
||||||
'{',
|
|
||||||
'}',
|
|
||||||
'[',
|
|
||||||
']',
|
|
||||||
'(',
|
|
||||||
')',
|
|
||||||
'#',
|
|
||||||
'+',
|
|
||||||
'-',
|
|
||||||
'!',
|
|
||||||
'|',
|
|
||||||
'<',
|
|
||||||
'>',
|
|
||||||
=> {
|
|
||||||
try writer.writeByte('\\');
|
try writer.writeByte('\\');
|
||||||
try writer.writeByte(c);
|
try writer.writeByte(c);
|
||||||
},
|
},
|
||||||
@@ -434,185 +411,108 @@ fn writeIndentation(level: usize, writer: *std.Io.Writer) anyerror!void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "markdown: basic" {
|
fn testMarkdownHTML(html: []const u8, expected: []const u8) !void {
|
||||||
const testing = @import("../testing.zig");
|
const testing = @import("../testing.zig");
|
||||||
const page = try testing.test_session.createPage();
|
const page = try testing.test_session.createPage();
|
||||||
defer testing.test_session.removePage();
|
defer testing.test_session.removePage();
|
||||||
const doc = page.window._document;
|
const doc = page.window._document;
|
||||||
|
|
||||||
const div = try doc.createElement("div", null, page);
|
const div = try doc.createElement("div", null, page);
|
||||||
try div.asNode().setTextContent("Hello world", page);
|
try page.parseHtmlAsChildren(div.asNode(), html);
|
||||||
|
|
||||||
var aw: std.Io.Writer.Allocating = .init(testing.allocator);
|
var aw: std.Io.Writer.Allocating = .init(testing.allocator);
|
||||||
defer aw.deinit();
|
defer aw.deinit();
|
||||||
try dump(div.asNode(), .{}, &aw.writer, page);
|
try dump(div.asNode(), .{}, &aw.writer, page);
|
||||||
|
|
||||||
try testing.expectString("Hello world\n", aw.written());
|
try testing.expectString(expected, aw.written());
|
||||||
|
}
|
||||||
|
|
||||||
|
test "markdown: basic" {
|
||||||
|
try testMarkdownHTML("Hello world", "Hello world\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
test "markdown: whitespace" {
|
test "markdown: whitespace" {
|
||||||
const testing = @import("../testing.zig");
|
try testMarkdownHTML("<span>A</span> <span>B</span>", "A B\n");
|
||||||
const page = try testing.test_session.createPage();
|
|
||||||
defer testing.test_session.removePage();
|
|
||||||
const doc = page.window._document;
|
|
||||||
|
|
||||||
const div = try doc.createElement("div", null, page);
|
|
||||||
|
|
||||||
const s1 = try doc.createElement("span", null, page);
|
|
||||||
try s1.asNode().setTextContent("A", page);
|
|
||||||
const s2 = try doc.createElement("span", null, page);
|
|
||||||
try s2.asNode().setTextContent("B", page);
|
|
||||||
|
|
||||||
_ = try div.asNode().appendChild(s1.asNode(), page);
|
|
||||||
// Add text node with space
|
|
||||||
const txt = try page.createTextNode(" ");
|
|
||||||
_ = try div.asNode().appendChild(txt, page);
|
|
||||||
_ = try div.asNode().appendChild(s2.asNode(), page);
|
|
||||||
|
|
||||||
var aw = std.Io.Writer.Allocating.init(testing.allocator);
|
|
||||||
defer aw.deinit();
|
|
||||||
try dump(div.asNode(), .{}, &aw.writer, page);
|
|
||||||
|
|
||||||
try testing.expectString("A B\n", aw.written());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test "markdown: escaping" {
|
test "markdown: escaping" {
|
||||||
const testing = @import("../testing.zig");
|
try testMarkdownHTML("<p># Not a header</p>", "\n\\# Not a header\n");
|
||||||
const page = try testing.test_session.createPage();
|
|
||||||
defer testing.test_session.removePage();
|
|
||||||
const doc = page.window._document;
|
|
||||||
|
|
||||||
const div = try doc.createElement("div", null, page);
|
|
||||||
|
|
||||||
const p = try doc.createElement("p", null, page);
|
|
||||||
try p.asNode().setTextContent("# Not a header", page);
|
|
||||||
_ = try div.asNode().appendChild(p.asNode(), page);
|
|
||||||
|
|
||||||
var aw: std.Io.Writer.Allocating = .init(testing.allocator);
|
|
||||||
defer aw.deinit();
|
|
||||||
try dump(div.asNode(), .{}, &aw.writer, page);
|
|
||||||
|
|
||||||
try testing.expectString("\n\\# Not a header\n", aw.written());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test "markdown: strikethrough" {
|
test "markdown: strikethrough" {
|
||||||
const testing = @import("../testing.zig");
|
try testMarkdownHTML("<s>deleted</s>", "~~deleted~~\n");
|
||||||
const page = try testing.test_session.createPage();
|
|
||||||
defer testing.test_session.removePage();
|
|
||||||
const doc = page.window._document;
|
|
||||||
|
|
||||||
const div = try doc.createElement("div", null, page);
|
|
||||||
|
|
||||||
const s = try doc.createElement("s", null, page);
|
|
||||||
try s.asNode().setTextContent("deleted", page);
|
|
||||||
_ = try div.asNode().appendChild(s.asNode(), page);
|
|
||||||
|
|
||||||
var aw: std.Io.Writer.Allocating = .init(testing.allocator);
|
|
||||||
defer aw.deinit();
|
|
||||||
try dump(div.asNode(), .{}, &aw.writer, page);
|
|
||||||
|
|
||||||
try testing.expectString("~~deleted~~\n", aw.written());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test "markdown: task list" {
|
test "markdown: task list" {
|
||||||
const testing = @import("../testing.zig");
|
try testMarkdownHTML(
|
||||||
const page = try testing.test_session.createPage();
|
\\<input type="checkbox" checked><input type="checkbox">
|
||||||
defer testing.test_session.removePage();
|
, "[x] [ ] \n");
|
||||||
const doc = page.window._document;
|
|
||||||
|
|
||||||
const div = try doc.createElement("div", null, page);
|
|
||||||
|
|
||||||
const input1 = try doc.createElement("input", null, page);
|
|
||||||
try input1.setAttributeSafe(comptime .wrap("type"), .wrap("checkbox"), page);
|
|
||||||
try input1.setAttributeSafe(comptime .wrap("checked"), .wrap(""), page);
|
|
||||||
_ = try div.asNode().appendChild(input1.asNode(), page);
|
|
||||||
|
|
||||||
const input2 = try doc.createElement("input", null, page);
|
|
||||||
try input2.setAttributeSafe(comptime .wrap("type"), .wrap("checkbox"), page);
|
|
||||||
_ = try div.asNode().appendChild(input2.asNode(), page);
|
|
||||||
|
|
||||||
var aw: std.Io.Writer.Allocating = .init(testing.allocator);
|
|
||||||
defer aw.deinit();
|
|
||||||
try dump(div.asNode(), .{}, &aw.writer, page);
|
|
||||||
|
|
||||||
try testing.expectString("[x] [ ] \n", aw.written());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test "markdown: ordered list" {
|
test "markdown: ordered list" {
|
||||||
const testing = @import("../testing.zig");
|
try testMarkdownHTML(
|
||||||
const page = try testing.test_session.createPage();
|
\\<ol><li>First</li><li>Second</li></ol>
|
||||||
defer testing.test_session.removePage();
|
, "1. First\n2. Second\n");
|
||||||
const doc = page.window._document;
|
|
||||||
|
|
||||||
const div = try doc.createElement("div", null, page);
|
|
||||||
|
|
||||||
const ol = try doc.createElement("ol", null, page);
|
|
||||||
_ = try div.asNode().appendChild(ol.asNode(), page);
|
|
||||||
|
|
||||||
const li1 = try doc.createElement("li", null, page);
|
|
||||||
try li1.asNode().setTextContent("First", page);
|
|
||||||
_ = try ol.asNode().appendChild(li1.asNode(), page);
|
|
||||||
|
|
||||||
const li2 = try doc.createElement("li", null, page);
|
|
||||||
try li2.asNode().setTextContent("Second", page);
|
|
||||||
_ = try ol.asNode().appendChild(li2.asNode(), page);
|
|
||||||
|
|
||||||
var aw: std.Io.Writer.Allocating = .init(testing.allocator);
|
|
||||||
defer aw.deinit();
|
|
||||||
try dump(div.asNode(), .{}, &aw.writer, page);
|
|
||||||
|
|
||||||
try testing.expectString("1. First\n2. Second\n", aw.written());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test "markdown: table" {
|
test "markdown: table" {
|
||||||
const testing = @import("../testing.zig");
|
try testMarkdownHTML(
|
||||||
const page = try testing.test_session.createPage();
|
\\<table><thead><tr><th>Head 1</th><th>Head 2</th></tr></thead>
|
||||||
defer testing.test_session.removePage();
|
\\<tbody><tr><td>Cell 1</td><td>Cell 2</td></tr></tbody></table>
|
||||||
const doc = page.window._document;
|
,
|
||||||
|
|
||||||
const div = try doc.createElement("div", null, page);
|
|
||||||
|
|
||||||
const table = try doc.createElement("table", null, page);
|
|
||||||
_ = try div.asNode().appendChild(table.asNode(), page);
|
|
||||||
|
|
||||||
const thead = try doc.createElement("thead", null, page);
|
|
||||||
_ = try table.asNode().appendChild(thead.asNode(), page);
|
|
||||||
|
|
||||||
const tr1 = try doc.createElement("tr", null, page);
|
|
||||||
_ = try thead.asNode().appendChild(tr1.asNode(), page);
|
|
||||||
|
|
||||||
const th1 = try doc.createElement("th", null, page);
|
|
||||||
try th1.asNode().setTextContent("Head 1", page);
|
|
||||||
_ = try tr1.asNode().appendChild(th1.asNode(), page);
|
|
||||||
|
|
||||||
const th2 = try doc.createElement("th", null, page);
|
|
||||||
try th2.asNode().setTextContent("Head 2", page);
|
|
||||||
_ = try tr1.asNode().appendChild(th2.asNode(), page);
|
|
||||||
|
|
||||||
const tbody = try doc.createElement("tbody", null, page);
|
|
||||||
_ = try table.asNode().appendChild(tbody.asNode(), page);
|
|
||||||
|
|
||||||
const tr2 = try doc.createElement("tr", null, page);
|
|
||||||
_ = try tbody.asNode().appendChild(tr2.asNode(), page);
|
|
||||||
|
|
||||||
const td1 = try doc.createElement("td", null, page);
|
|
||||||
try td1.asNode().setTextContent("Cell 1", page);
|
|
||||||
_ = try tr2.asNode().appendChild(td1.asNode(), page);
|
|
||||||
|
|
||||||
const td2 = try doc.createElement("td", null, page);
|
|
||||||
try td2.asNode().setTextContent("Cell 2", page);
|
|
||||||
_ = try tr2.asNode().appendChild(td2.asNode(), page);
|
|
||||||
|
|
||||||
var aw: std.Io.Writer.Allocating = .init(testing.allocator);
|
|
||||||
defer aw.deinit();
|
|
||||||
try dump(div.asNode(), .{}, &aw.writer, page);
|
|
||||||
|
|
||||||
const expected =
|
|
||||||
\\
|
\\
|
||||||
\\| Head 1 | Head 2 |
|
\\| Head 1 | Head 2 |
|
||||||
\\|---|---|
|
\\|---|---|
|
||||||
\\| Cell 1 | Cell 2 |
|
\\| Cell 1 | Cell 2 |
|
||||||
\\
|
\\
|
||||||
;
|
);
|
||||||
try testing.expectString(expected, aw.written());
|
}
|
||||||
|
|
||||||
|
test "markdown: nested lists" {
|
||||||
|
try testMarkdownHTML(
|
||||||
|
\\<ul><li>Parent<ul><li>Child</li></ul></li></ul>
|
||||||
|
,
|
||||||
|
\\- Parent
|
||||||
|
\\ - Child
|
||||||
|
\\
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "markdown: blockquote" {
|
||||||
|
try testMarkdownHTML("<blockquote>Hello world</blockquote>", "\n> Hello world\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
test "markdown: links" {
|
||||||
|
try testMarkdownHTML("<a href=\"https://lightpanda.io\">Lightpanda</a>", "[Lightpanda](https://lightpanda.io)\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
test "markdown: images" {
|
||||||
|
try testMarkdownHTML("<img src=\"logo.png\" alt=\"Logo\">", "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
test "markdown: headings" {
|
||||||
|
try testMarkdownHTML("<h1>Title</h1><h2>Subtitle</h2>",
|
||||||
|
\\
|
||||||
|
\\# Title
|
||||||
|
\\
|
||||||
|
\\## Subtitle
|
||||||
|
\\
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "markdown: code" {
|
||||||
|
try testMarkdownHTML(
|
||||||
|
\\<p>Use git push</p>
|
||||||
|
\\<pre><code>line 1
|
||||||
|
\\line 2</code></pre>
|
||||||
|
,
|
||||||
|
\\
|
||||||
|
\\Use git push
|
||||||
|
\\
|
||||||
|
\\```
|
||||||
|
\\line 1
|
||||||
|
\\line 2
|
||||||
|
\\```
|
||||||
|
\\
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user