clone of repo on github
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

284 lines
10 KiB

/**
* TDD Tests for NKBIP-01 Publication Tree Processor
*
* Tests the iterative parsing function at different hierarchy levels
* using deep_hierarchy_test.adoc to verify NKBIP-01 compliance.
*/
import { describe, it, expect, beforeAll } from 'vitest';
import { readFileSync } from 'fs';
import { parseAsciiDocWithTree, validateParseLevel, getSupportedParseLevels } from '../../src/lib/utils/asciidoc_publication_parser.js';
// Mock NDK for testing
const mockNDK = {
activeUser: {
pubkey: "test-pubkey-12345"
}
} as any;
// Read the test document
const testDocumentPath = "./test_data/AsciidocFiles/deep_hierarchy_test.adoc";
let testContent: string;
try {
testContent = readFileSync(testDocumentPath, 'utf-8');
} catch (error) {
console.error("Failed to read test document:", error);
testContent = `= Deep Hierarchical Document Test
:tags: testing, hierarchy, structure
:author: Test Author
:type: technical
This document tests all 6 levels of AsciiDoc hierarchy to validate our parse level system.
== Level 2: Main Sections
:tags: level2, main
This is a level 2 section that should appear in all parse levels.
=== Level 3: Subsections
:tags: level3, subsection
This is a level 3 section that should appear in parse levels 3-6.
==== Level 4: Sub-subsections
:tags: level4, detailed
This is a level 4 section that should appear in parse levels 4-6.
===== Level 5: Deep Subsections
:tags: level5, deep
This is a level 5 section that should only appear in parse levels 5-6.
====== Level 6: Deepest Level
:tags: level6, deepest
This is a level 6 section that should only appear in parse level 6.
Content at the deepest level of our hierarchy.
== Level 2: Second Main Section
:tags: level2, main, second
A second main section to ensure we have balanced content at the top level.`;
}
describe("NKBIP-01 Publication Tree Processor", () => {
it("should validate parse levels correctly", () => {
// Test valid parse levels
expect(validateParseLevel(2)).toBe(true);
expect(validateParseLevel(3)).toBe(true);
expect(validateParseLevel(5)).toBe(true);
// Test invalid parse levels
expect(validateParseLevel(1)).toBe(false);
expect(validateParseLevel(6)).toBe(false);
expect(validateParseLevel(7)).toBe(false);
expect(validateParseLevel(2.5)).toBe(false);
expect(validateParseLevel(-1)).toBe(false);
// Test supported levels array
const supportedLevels = getSupportedParseLevels();
expect(supportedLevels).toEqual([2, 3, 4, 5]);
});
it("should parse Level 2 with NKBIP-01 minimal structure", async () => {
const result = await parseAsciiDocWithTree(testContent, mockNDK, 2);
// Should be detected as article (has title and sections)
expect(result.metadata.contentType).toBe("article");
expect(result.metadata.parseLevel).toBe(2);
expect(result.metadata.title).toBe("Deep Hierarchical Document Test");
// Should have 1 index event (30040) + 2 content events (30041) for level 2 sections
expect(result.indexEvent).toBeDefined();
expect(result.indexEvent?.kind).toBe(30040);
expect(result.contentEvents.length).toBe(2);
// All content events should be kind 30041
result.contentEvents.forEach(event => {
expect(event.kind).toBe(30041);
});
// Check titles of level 2 sections
const contentTitles = result.contentEvents.map(e =>
e.tags.find((t: string[]) => t[0] === "title")?.[1]
);
expect(contentTitles).toContain("Level 2: Main Sections");
expect(contentTitles).toContain("Level 2: Second Main Section");
// Content should include all nested subsections as AsciiDoc
const firstSectionContent = result.contentEvents[0].content;
expect(firstSectionContent).toBeDefined();
// Should contain level 3, 4, 5 content as nested AsciiDoc markup
expect(firstSectionContent.includes("=== Level 3: Subsections")).toBe(true);
expect(firstSectionContent.includes("==== Level 4: Sub-subsections")).toBe(true);
expect(firstSectionContent.includes("===== Level 5: Deep Subsections")).toBe(true);
});
it("should parse Level 3 with NKBIP-01 intermediate structure", async () => {
const result = await parseAsciiDocWithTree(testContent, mockNDK, 3);
expect(result.metadata.contentType).toBe("article");
expect(result.metadata.parseLevel).toBe(3);
// Should have hierarchical structure
expect(result.indexEvent).toBeDefined();
expect(result.indexEvent?.kind).toBe(30040);
// Should have mix of 30040 (for level 2 sections with children) and 30041 (for content)
const kinds = result.contentEvents.map(e => e.kind);
expect(kinds).toContain(30040); // Level 2 sections with children
expect(kinds).toContain(30041); // Level 3 content sections
// Level 2 sections with children should be 30040 index events
const level2WithChildrenEvents = result.contentEvents.filter(e =>
e.kind === 30040 &&
e.tags.find((t: string[]) => t[0] === "title")?.[1]?.includes("Level 2:")
);
expect(level2WithChildrenEvents.length).toBe(2); // Both level 2 sections have children
// Should have 30041 events for level 3 content
const level3ContentEvents = result.contentEvents.filter(e =>
e.kind === 30041 &&
e.tags.find((t: string[]) => t[0] === "title")?.[1]?.includes("Level 3:")
);
expect(level3ContentEvents.length).toBeGreaterThan(0);
});
it("should parse Level 4 with NKBIP-01 detailed structure", async () => {
const result = await parseAsciiDocWithTree(testContent, mockNDK, 4);
expect(result.metadata.contentType).toBe("article");
expect(result.metadata.parseLevel).toBe(4);
// Should have hierarchical structure with mix of 30040 and 30041 events
expect(result.indexEvent).toBeDefined();
expect(result.indexEvent?.kind).toBe(30040);
const kinds = result.contentEvents.map(e => e.kind);
expect(kinds).toContain(30040); // Level 2 sections with children
expect(kinds).toContain(30041); // Content sections
// Check that we have level 4 content sections
const contentTitles = result.contentEvents.map(e =>
e.tags.find((t: string[]) => t[0] === "title")?.[1]
);
expect(contentTitles).toContain("Level 4: Sub-subsections");
});
it("should parse Level 5 with NKBIP-01 maximum depth", async () => {
const result = await parseAsciiDocWithTree(testContent, mockNDK, 5);
expect(result.metadata.contentType).toBe("article");
expect(result.metadata.parseLevel).toBe(5);
// Should have hierarchical structure
expect(result.indexEvent).toBeDefined();
expect(result.indexEvent?.kind).toBe(30040);
// Should include level 5 sections as content events
const contentTitles = result.contentEvents.map(e =>
e.tags.find((t: string[]) => t[0] === "title")?.[1]
);
expect(contentTitles).toContain("Level 5: Deep Subsections");
});
it("should validate event structure correctly", async () => {
const result = await parseAsciiDocWithTree(testContent, mockNDK, 3);
// Test index event structure
expect(result.indexEvent).toBeDefined();
expect(result.indexEvent?.kind).toBe(30040);
expect(result.indexEvent?.tags).toBeDefined();
// Check required tags
const indexTags = result.indexEvent!.tags;
const dTag = indexTags.find((t: string[]) => t[0] === "d");
const titleTag = indexTags.find((t: string[]) => t[0] === "title");
expect(dTag).toBeDefined();
expect(titleTag).toBeDefined();
expect(titleTag![1]).toBe("Deep Hierarchical Document Test");
// Test content events structure - mix of 30040 and 30041
result.contentEvents.forEach(event => {
expect([30040, 30041]).toContain(event.kind);
expect(event.tags).toBeDefined();
expect(event.content).toBeDefined();
const eventTitleTag = event.tags.find((t: string[]) => t[0] === "title");
expect(eventTitleTag).toBeDefined();
});
});
it("should preserve content as AsciiDoc", async () => {
const result = await parseAsciiDocWithTree(testContent, mockNDK, 2);
// Content should be preserved as original AsciiDoc, not converted to HTML
const firstEvent = result.contentEvents[0];
expect(firstEvent.content).toBeDefined();
// Should contain AsciiDoc markup, not HTML
expect(firstEvent.content.includes("<")).toBe(false);
expect(firstEvent.content.includes("===")).toBe(true);
});
it("should handle attributes correctly", async () => {
const result = await parseAsciiDocWithTree(testContent, mockNDK, 2);
// Document-level attributes should be in index event
expect(result.indexEvent).toBeDefined();
const indexTags = result.indexEvent!.tags;
// Check for document attributes
const authorTag = indexTags.find((t: string[]) => t[0] === "author");
const typeTag = indexTags.find((t: string[]) => t[0] === "type");
const tagsTag = indexTags.find((t: string[]) => t[0] === "t");
expect(authorTag?.[1]).toBe("Test Author");
expect(typeTag?.[1]).toBe("technical");
expect(tagsTag).toBeDefined(); // Should have at least one t-tag
});
it("should handle scattered notes mode", async () => {
// Test with content that has no document title (scattered notes)
const scatteredContent = `== First Note
:tags: note1
Content of first note.
== Second Note
:tags: note2
Content of second note.`;
const result = await parseAsciiDocWithTree(scatteredContent, mockNDK, 2);
expect(result.metadata.contentType).toBe("scattered-notes");
expect(result.indexEvent).toBeNull(); // No index event for scattered notes
expect(result.contentEvents.length).toBe(2);
// All events should be 30041 content events
result.contentEvents.forEach(event => {
expect(event.kind).toBe(30041);
});
});
it("should integrate with PublicationTree structure", async () => {
const result = await parseAsciiDocWithTree(testContent, mockNDK, 2);
// Should have a PublicationTree instance
expect(result.tree).toBeDefined();
// Tree should have methods for event management
expect(typeof result.tree.addEvent).toBe("function");
// Event structure should be populated
expect(result.metadata.eventStructure).toBeDefined();
expect(Array.isArray(result.metadata.eventStructure)).toBe(true);
});
});