Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

145 lines
4.4 KiB
Go

package languages
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zzet/gortex/internal/graph"
)
const proseDoc = "# Project\n" +
"\n" +
"An intro paragraph about the project.\n" +
"\n" +
"## Setup\n" +
"\n" +
"Run the installer before anything else.\n" +
"\n" +
"### Build\n" +
"\n" +
"Compile with the standard toolchain and link the binary.\n" +
"\n" +
"## Usage\n" +
"\n" +
"Invoke the command with a config file.\n"
func docNodes(nodes []*graph.Node) []*graph.Node {
var out []*graph.Node
for _, n := range nodes {
if n.Kind == graph.KindDoc {
out = append(out, n)
}
}
return out
}
func TestMarkdownProse_SectionExtraction(t *testing.T) {
e := NewMarkdownExtractor()
result, err := e.Extract("README.md", []byte(proseDoc))
require.NoError(t, err)
docs := docNodes(result.Nodes)
require.NotEmpty(t, docs, "prose extraction should emit KindDoc nodes")
byName := map[string]*graph.Node{}
for _, d := range docs {
byName[d.Name] = d
}
// Heading-path breadcrumb names.
require.Contains(t, byName, "README.md > Project")
require.Contains(t, byName, "README.md > Project > Setup")
require.Contains(t, byName, "README.md > Project > Setup > Build")
require.Contains(t, byName, "README.md > Project > Usage")
// The Build section's body is the section paragraph, markdown
// stripped.
build := byName["README.md > Project > Setup > Build"]
bodyText, _ := build.Meta["section_text"].(string)
assert.Contains(t, bodyText, "Compile with the standard toolchain")
// The deeper Build heading must NOT absorb the parent Setup prose.
assert.NotContains(t, bodyText, "Run the installer")
// heading_path meta is the crumb slice.
hp, _ := build.Meta["heading_path"].([]string)
assert.Equal(t, []string{"Project", "Setup", "Build"}, hp)
// Line ranges are populated and sane.
assert.Greater(t, build.StartLine, 0)
assert.GreaterOrEqual(t, build.EndLine, build.StartLine)
}
func TestMarkdownProse_StableIDs(t *testing.T) {
e := NewMarkdownExtractor()
r1, err := e.Extract("README.md", []byte(proseDoc))
require.NoError(t, err)
// Re-extract the SAME doc with extra blank lines inserted at the
// top -- every section shifts down, but the IDs (keyed on the
// heading path, not line numbers) must be identical.
shifted := "\n\n\n" + proseDoc
r2, err := e.Extract("README.md", []byte(shifted))
require.NoError(t, err)
ids := func(nodes []*graph.Node) map[string]bool {
m := map[string]bool{}
for _, n := range docNodes(nodes) {
m[n.ID] = true
}
return m
}
id1, id2 := ids(r1.Nodes), ids(r2.Nodes)
require.Equal(t, id1, id2, "section IDs must be stable across a line-shifting edit")
// IDs are heading-path derived, file-prefixed.
for id := range id1 {
assert.Contains(t, id, "README.md::doc:")
}
}
func TestMarkdownProse_PreambleCaptured(t *testing.T) {
// Prose before the first heading is not lost.
e := NewMarkdownExtractor()
doc := "Leading prose with no heading above it.\n\n# Title\n\nBody.\n"
result, err := e.Extract("notes.md", []byte(doc))
require.NoError(t, err)
var preamble *graph.Node
for _, d := range docNodes(result.Nodes) {
if txt, _ := d.Meta["section_text"].(string); txt == "Leading prose with no heading above it." {
preamble = d
}
}
require.NotNil(t, preamble, "leading prose should be captured in a preamble section")
}
func TestMarkdownProse_EmptySectionsSkipped(t *testing.T) {
// A heading with no prose body carries no search signal -- it
// should not produce a KindDoc node.
e := NewMarkdownExtractor()
doc := "# Only A Heading\n\n## Another Bare Heading\n"
result, err := e.Extract("bare.md", []byte(doc))
require.NoError(t, err)
assert.Empty(t, docNodes(result.Nodes),
"headings with no prose body should not emit KindDoc nodes")
}
func TestMarkdownProse_InlineSyntaxStripped(t *testing.T) {
e := NewMarkdownExtractor()
doc := "# Doc\n\nSee the [install guide](setup.md) and run `make build` for **details**.\n"
result, err := e.Extract("d.md", []byte(doc))
require.NoError(t, err)
docs := docNodes(result.Nodes)
require.Len(t, docs, 1)
body, _ := docs[0].Meta["section_text"].(string)
// Link text kept, URL dropped; inline code unwrapped; emphasis
// markers removed.
assert.Contains(t, body, "install guide")
assert.NotContains(t, body, "setup.md")
assert.NotContains(t, body, "`")
assert.NotContains(t, body, "**")
assert.Contains(t, body, "make build")
}