2026-06-25 20:16:16 +08:00
|
|
|
|
//go:build cgo && integration
|
|
|
|
|
|
|
2026-07-02 09:46:33 +08:00
|
|
|
|
package pdf
|
2026-06-25 20:16:16 +08:00
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"context"
|
|
|
|
|
|
"strings"
|
|
|
|
|
|
"testing"
|
|
|
|
|
|
|
2026-06-29 18:46:41 +08:00
|
|
|
|
pdf "ragflow/internal/deepdoc/parser/pdf/type"
|
|
|
|
|
|
)
|
2026-06-25 20:16:16 +08:00
|
|
|
|
|
2026-06-29 18:46:41 +08:00
|
|
|
|
// TestIntegration_DeepDoc_TableStructure verifies that parsing a PDF
|
|
|
|
|
|
// through the OSS TableBuilder produces tables with the expected row/column structure.
|
|
|
|
|
|
func TestIntegration_DeepDoc_TableStructure(t *testing.T) {
|
|
|
|
|
|
client := mustConnectInferenceClient(t)
|
2026-07-02 09:46:33 +08:00
|
|
|
|
data := mustReadPDF(t, "06_table_content.pdf")
|
2026-06-25 20:16:16 +08:00
|
|
|
|
|
2026-06-29 18:46:41 +08:00
|
|
|
|
cfg := pdf.DefaultParserConfig()
|
2026-07-02 09:46:33 +08:00
|
|
|
|
p := NewParser(cfg)
|
|
|
|
|
|
result, err := p.Parse(context.Background(), data, client)
|
2026-06-25 20:16:16 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatalf("Parse: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if len(result.Tables) == 0 {
|
|
|
|
|
|
t.Skip("DLA did not detect any tables in fixture")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-02 09:46:33 +08:00
|
|
|
|
t.Logf("DeepDoc produced %d tables", len(result.Tables))
|
2026-06-25 20:16:16 +08:00
|
|
|
|
for i, tbl := range result.Tables {
|
|
|
|
|
|
t.Logf("table[%d]: %d rows", i, len(tbl.Rows))
|
|
|
|
|
|
for ri, row := range tbl.Rows {
|
|
|
|
|
|
hasContent := false
|
|
|
|
|
|
for _, cell := range row {
|
|
|
|
|
|
if strings.TrimSpace(cell) != "" {
|
|
|
|
|
|
hasContent = true
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if !hasContent {
|
|
|
|
|
|
t.Errorf("table[%d] row[%d]: all cells empty", i, ri)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-29 18:46:41 +08:00
|
|
|
|
// TestIntegration_DeepDoc_TableRows verifies each table has non-empty
|
2026-06-25 20:16:16 +08:00
|
|
|
|
// rows with the expected grid structure.
|
2026-06-29 18:46:41 +08:00
|
|
|
|
func TestIntegration_DeepDoc_TableRows(t *testing.T) {
|
|
|
|
|
|
client := mustConnectInferenceClient(t)
|
2026-07-02 09:46:33 +08:00
|
|
|
|
data := mustReadPDF(t, "06_table_content.pdf")
|
2026-06-25 20:16:16 +08:00
|
|
|
|
|
2026-06-29 18:46:41 +08:00
|
|
|
|
cfg := pdf.DefaultParserConfig()
|
2026-07-02 09:46:33 +08:00
|
|
|
|
p := NewParser(cfg)
|
|
|
|
|
|
result, err := p.Parse(context.Background(), data, client)
|
2026-06-25 20:16:16 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatalf("Parse: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
if len(result.Tables) == 0 {
|
|
|
|
|
|
t.Skip("DLA did not detect any tables in fixture")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for i, tbl := range result.Tables {
|
|
|
|
|
|
if len(tbl.Rows) == 0 {
|
|
|
|
|
|
t.Errorf("table[%d]: no rows", i)
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
t.Logf("table[%d]: %d rows × ~%d cols", i, len(tbl.Rows), len(tbl.Rows[0]))
|
|
|
|
|
|
for ri, row := range tbl.Rows {
|
|
|
|
|
|
hasContent := false
|
|
|
|
|
|
for _, cell := range row {
|
|
|
|
|
|
if strings.TrimSpace(cell) != "" {
|
|
|
|
|
|
hasContent = true
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if !hasContent {
|
|
|
|
|
|
t.Errorf("table[%d] row[%d]: all cells empty", i, ri)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-29 18:46:41 +08:00
|
|
|
|
// TestIntegration_DeepDoc_Idempotency verifies that parsing the same PDF
|
2026-06-25 20:16:16 +08:00
|
|
|
|
// twice produces the same table row structure.
|
2026-06-29 18:46:41 +08:00
|
|
|
|
func TestIntegration_DeepDoc_Idempotency(t *testing.T) {
|
|
|
|
|
|
client := mustConnectInferenceClient(t)
|
2026-06-25 20:16:16 +08:00
|
|
|
|
|
2026-06-29 18:46:41 +08:00
|
|
|
|
parseOnce := func() *pdf.ParseResult {
|
2026-07-02 09:46:33 +08:00
|
|
|
|
data := mustReadPDF(t, "06_table_content.pdf")
|
2026-06-25 20:16:16 +08:00
|
|
|
|
|
2026-06-29 18:46:41 +08:00
|
|
|
|
cfg := pdf.DefaultParserConfig()
|
2026-07-02 09:46:33 +08:00
|
|
|
|
p := NewParser(cfg)
|
|
|
|
|
|
result, err := p.Parse(context.Background(), data, client)
|
2026-06-25 20:16:16 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatalf("Parse: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
return result
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
r1 := parseOnce()
|
|
|
|
|
|
r2 := parseOnce()
|
|
|
|
|
|
|
|
|
|
|
|
if len(r1.Tables) != len(r2.Tables) {
|
|
|
|
|
|
t.Errorf("table count mismatch: run1=%d run2=%d", len(r1.Tables), len(r2.Tables))
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
for i := 0; i < len(r1.Tables); i++ {
|
|
|
|
|
|
if len(r1.Tables[i].Rows) != len(r2.Tables[i].Rows) {
|
|
|
|
|
|
t.Errorf("table[%d] row count differs: run1=%d run2=%d", i,
|
|
|
|
|
|
len(r1.Tables[i].Rows), len(r2.Tables[i].Rows))
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-29 18:46:41 +08:00
|
|
|
|
// TestIntegration_DeepDoc_EmptyPage verifies that a page with no tables
|
2026-06-25 20:16:16 +08:00
|
|
|
|
// does not crash.
|
2026-06-29 18:46:41 +08:00
|
|
|
|
func TestIntegration_DeepDoc_EmptyPage(t *testing.T) {
|
|
|
|
|
|
client := mustConnectInferenceClient(t)
|
2026-07-02 09:46:33 +08:00
|
|
|
|
data := mustReadPDF(t, "01_english_simple.pdf")
|
2026-06-25 20:16:16 +08:00
|
|
|
|
|
2026-06-29 18:46:41 +08:00
|
|
|
|
cfg := pdf.DefaultParserConfig()
|
2026-07-02 09:46:33 +08:00
|
|
|
|
p := NewParser(cfg)
|
|
|
|
|
|
_, err := p.Parse(context.Background(), data, client)
|
2026-06-25 20:16:16 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
t.Fatalf("Parse: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|