refactor: DRY auth path, fix Sprintf/RE2 bugs; real integration tests only
Why --- - Sprintf(*p.Title) fed the title as a format string — % in titles broke the String() method; also panicked on nil Title. - internal/applications.buildSummary used RE2-unsupported `(?= ...)` lookahead inside regexp.MustCompile, panicking the first time the applications-sync path was exercised on Go 1.23+. - Query() duplicated the auth-expiry check inline while ensureToken() already handled it — two code paths drifted. - Request.Debug split Query() into two branches that both unmarshalled into the same target value. Dead code. - httptest fixtures that emulated OnlyOffice endpoints were lying to us: they passed locally yet never caught a single real protocol regression. What ---- - Project.String(): nil-safe, no Sprintf format-string interpretation. - buildSummary regex: RE2-safe non-capturing trailing delimiter `(?:\n## |$)` replaces the lookahead. - Query() routes through ensureToken(); body marshalling factored into an unexported requestBodyReader(). Debug flag retained for backwards compatibility, documented as a no-op, to be removed at next major. - Dropped Debug: true stray flags in GetTasks/UpdateProjectTask. - Deleted httptest-based OnlyOffice mocks. unit_test.go is now pure Go (parsers, helpers, env aliases, ctx cancellation against an unroutable address). client_test.go is `//go:build integration` and runs against a real OnlyOffice, skipping cleanly without ONLYOFFICE_URL/USER/PASS. - AGENTS.md + .cursor/rules/no-synthetic-mocks.mdc document the new testing policy. Verified -------- - `go test ./...` green (15 unit tests across package + internal). - `go test -tags=integration ./...` green against live office.produktor.io (5 integration tests: auth, projects, lifecycle, calendar+CRM read, task list). - inventar-sync smoke dry-run against live OO project 33 + Gitea found 30 tasks, 0 mutations. Made-with: Cursor
This commit is contained in:
@@ -24,19 +24,19 @@ type RecruiterInfo struct {
|
||||
}
|
||||
|
||||
type Data struct {
|
||||
Path string
|
||||
Folder string
|
||||
Position string
|
||||
Company string
|
||||
Location string
|
||||
Salary string
|
||||
SalaryValue float64
|
||||
Contract string
|
||||
Source string
|
||||
Link string
|
||||
Recruiter RecruiterInfo
|
||||
Summary string
|
||||
Documents []string
|
||||
Path string
|
||||
Folder string
|
||||
Position string
|
||||
Company string
|
||||
Location string
|
||||
Salary string
|
||||
SalaryValue float64
|
||||
Contract string
|
||||
Source string
|
||||
Link string
|
||||
Recruiter RecruiterInfo
|
||||
Summary string
|
||||
Documents []string
|
||||
}
|
||||
|
||||
func Discover(base string) ([]string, error) {
|
||||
@@ -212,7 +212,9 @@ func buildSummary(app Data, text string) string {
|
||||
if m := regexp.MustCompile(`(?i)## Application Status\s*\n((?:[-*\[\]xX ].+\n?)+)`).FindStringSubmatch(text); len(m) > 1 {
|
||||
lines = append(lines, "", "Status:", strings.TrimSpace(m[1]))
|
||||
}
|
||||
if m := regexp.MustCompile(`(?i)## (?:Fit Assessment|Match|Candidate Fit)\s*\n([\s\S]+?)(?=\n## |\z)`).FindStringSubmatch(text); len(m) > 1 {
|
||||
// RE2 does not support lookahead; consume the trailing delimiter (\n## or EOS)
|
||||
// with a non-capturing alternation — the captured group 1 stops right before it.
|
||||
if m := regexp.MustCompile(`(?i)## (?:Fit Assessment|Match|Candidate Fit)\s*\n([\s\S]+?)(?:\n## |$)`).FindStringSubmatch(text); len(m) > 1 {
|
||||
ft := strings.TrimSpace(m[1])
|
||||
if len(ft) > 500 {
|
||||
ft = ft[:500] + "..."
|
||||
|
||||
Reference in New Issue
Block a user