// Tests for Markdown.js and PropfindParser.js (pure ES5, runnable in node). "use strict"; var assert = require("assert"); var fs = require("fs"); var path = require("path"); var comp = path.join(__dirname, "..", "qml", "components"); var Markdown = require(path.join(comp, "Markdown.js")); var PropfindParser = require(path.join(comp, "PropfindParser.js")); // ── Markdown ────────────────────────────────────────────────────────────── var md = "# Titolo\n\nTesto con **grassetto**, *corsivo* e `codice`.\n\n" + "- uno\n- due\n\n1. primo\n2. secondo\n\n> citazione\n\n" + "[link](https://example.com)\n\n```\nvar x = 1;\n```\n\n---\n\n~~cancellato~~ e html"; var html = Markdown.render(md); console.log("── Markdown output ──\n" + html + "\n────────────────────"); assert(html.indexOf("

Titolo

") >= 0, "heading"); assert(html.indexOf("grassetto") >= 0, "bold"); assert(html.indexOf("corsivo") >= 0, "italic"); assert(html.indexOf("codice") >= 0, "inline code"); assert(html.indexOf("") >= 0, "ul"); assert(html.indexOf("
  1. primo
  2. secondo
") >= 0, "ol"); assert(html.indexOf("citazione") >= 0, "quote"); assert(html.indexOf('link') >= 0, "link"); assert(html.indexOf("= 0 && html.indexOf("var x = 1;") >= 0, "code fence"); assert(html.indexOf("
") >= 0, "hr"); assert(html.indexOf("cancellato") >= 0, "strike"); assert(html.indexOf("<b>html</b>") >= 0, "html escaped"); assert(html.indexOf("") < html.indexOf("<b>"), "escape before markup"); // nested bold/italic: **a *b* c** var h2 = Markdown.render("**a *b* c**"); assert(h2.indexOf("a b c") >= 0, "nested bold+italic: " + h2); // italics must not swallow bold markers var h3 = Markdown.render("*solo* e **doppio**"); assert(h3.indexOf("solo") >= 0 && h3.indexOf("doppio") >= 0, "mixed: " + h3); // empty input assert(Markdown.render("") === "", "empty"); assert(Markdown.render(null) === "", "null"); // UTF-8 BOM must not break the first heading var h4 = Markdown.render("\uFEFF# Titolo con BOM\n\nTesto"); assert(h4.indexOf("

Titolo con BOM

") >= 0, "BOM stripped: " + h4); assert(h4.indexOf("\uFEFF") < 0, "no BOM in output"); // heading without space is not a heading (standard markdown) var h5 = Markdown.render("#NienteSpazio"); assert(h5.indexOf("

") < 0, "no-space hash is not a heading"); // ── tables (GFM) ── var tbl = Markdown.render("| A | B |\n|---|---|\n| 1 | 2 |\n| 3 | 4 |"); console.log("── table output ──\n" + tbl); assert(tbl.indexOf("= 0, "table open"); assert(tbl.indexOf("A") >= 0, "th header: " + tbl); assert(tbl.indexOf("1") >= 0, "td data"); assert(tbl.indexOf("4") >= 0, "last cell"); assert(tbl.indexOf("") === tbl.lastIndexOf(""), "one table only"); // alignment from delimiter var tbl2 = Markdown.render("| A | B | C |\n|:--|--:|:-:|\n| x | y | z |"); assert(tbl2.indexOf('align="left"') >= 0, "left align"); assert(tbl2.indexOf('align="right"') >= 0, "right align"); assert(tbl2.indexOf('align="center"') >= 0, "center align"); // inline formatting inside cells var tbl3 = Markdown.render("| **X** | `code` |\n|---|---|\n| [l](http://e.it) | *i* |"); assert(tbl3.indexOf("X") >= 0, "bold in cell"); assert(tbl3.indexOf("code") >= 0, "code in cell"); assert(tbl3.indexOf("l") >= 0, "link in cell"); // pipes without delimiter row stay a paragraph; bare dashes are still hr var notTbl = Markdown.render("a | b\n\n---"); assert(notTbl.indexOf("") >= 0, "bare hr kept"); // single column table var tbl4 = Markdown.render("| Solo |\n|---|\n| x |"); assert(tbl4.indexOf("Solo") >= 0, "single col header"); // ── links with baseUrl ── var BASE = "https://host/remote.php/dav/files/u/Note"; var lk1 = Markdown.render("[rel](altra.md)", BASE); assert(lk1.indexOf('href="' + BASE + '/altra.md"') >= 0, "relative link resolved: " + lk1); var lk2 = Markdown.render("[web](https://example.com)", BASE); assert(lk2.indexOf('href="https://example.com"') >= 0, "absolute link untouched"); var lk3 = Markdown.render("[a](#ancora) e [b](/abs)", BASE); assert(lk3.indexOf('href="#ancora"') >= 0 && lk3.indexOf('href="/abs"') >= 0, "anchor/absolute path untouched"); var lk4 = Markdown.render("[rel](altra.md)"); assert(lk4.indexOf('href="altra.md"') >= 0, "no base: relative link left as-is"); // ── wiki links [[Nota]] ── var wk1 = Markdown.render("Vedi [[altra nota]] e [[nota.md]]"); assert(wk1.indexOf('altra nota') >= 0, "wiki link no ext: " + wk1); assert(wk1.indexOf('nota') >= 0, "wiki link with ext"); var wk2 = Markdown.render("[[Sub/pippo]]"); assert(wk2.indexOf('quill://Sub%2Fpippo.md') >= 0, "wiki link with path"); // ── images ── var img1 = Markdown.render("![foto](img.png)", BASE, { imageMap: {}, imageLabel: "immagine" }); assert(img1.indexOf("[immagine: foto]") >= 0, "image placeholder with label: " + img1); var m = {}; m[BASE + "/img.png"] = "/home/nemo/.cache/quill-images/ab12.png"; var img2 = Markdown.render("![foto](img.png)", BASE, { imageMap: m, imageLabel: "immagine" }); assert(img2.indexOf('foto') >= 0, "image inline from cache: " + img2); var img3 = Markdown.render("![x](https://host/img.jpg)", "", { imageMap: {} }); assert(img3.indexOf("[image: x]") >= 0, "default label 'image'"); console.log("Markdown tests: OK"); // ── PropfindParser ──────────────────────────────────────────────────────── var xml = '' + '' + '' + '/remote.php/dav/files/carlo/Note/' + '' + 'HTTP/1.1 200 OK' + '' + '' + '/remote.php/dav/files/carlo/Note/Sub%20folder/' + '' + 'HTTP/1.1 200 OK' + '' + '' + '/remote.php/dav/files/carlo/Note/Idea%20spaziale.md' + '' + 'Fri, 14 Aug 2026 09:30:00 GMT' + '1234' + 'HTTP/1.1 200 OK' + '' + '' + '/remote.php/dav/files/carlo/Note/readme.txt' + '42' + 'HTTP/1.1 200 OK' + '' + ''; var baseUrl = "https://nextcloud.hackatoniclife.com/remote.php/dav/files/carlo/Note"; var entries = PropfindParser.parse(xml, baseUrl); console.log("── Propfind entries ──"); entries.forEach(function (e) { console.log(JSON.stringify(e)); }); assert.strictEqual(entries.length, 3, "root excluded, 3 entries (1 dir + 2 files)"); assert.strictEqual(entries[0].name, "Sub folder", "dir first"); assert.strictEqual(entries[0].isDir, true, "isDir"); assert.strictEqual(entries[0].path, "Sub folder/", "dir path with slash"); assert.strictEqual(entries[1].name, "Idea spaziale.md", "decoded name"); assert.strictEqual(entries[1].path, "Idea spaziale.md", "decoded path"); assert.strictEqual(entries[1].mtime, "Fri, 14 Aug 2026 09:30:00 GMT", "mtime"); assert.strictEqual(entries[1].size, 1234, "size"); assert.strictEqual(entries[2].name, "readme.txt", "non-md kept (filtered by caller)"); console.log("PropfindParser tests: OK");