Add Phase 2+3 features: antonyms, backing, pronunciation, etymology, difficulty, affix expansion
New endpoints: /antonyms, /backing, /pronunciation, /etymology with difficulty scoring on /random. Cross-language synset backing links French/Portuguese words to English equivalents via WordNet 3.0 synset IDs (matching WOLF and OMW offsets). New loaders: Hunspell affix expansion (fr, pt-PT), English programmatic inflector, CMU Pronouncing Dictionary, SUBTLEX-US frequency, CETEMPúblico frequency, Open Multilingual Wordnet (Portuguese), and SQL-based difficulty scoring. Schema v2 adds tables: antonyms, synsets, word_synsets, pronunciations, etymology with migration support for existing databases. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
108
cmd/server/bench_test.go
Normal file
108
cmd/server/bench_test.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"dreamdict/internal/dictionary"
|
||||
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
func setupBenchServer(b *testing.B) *http.ServeMux {
|
||||
b.Helper()
|
||||
db, err := sql.Open("sqlite", ":memory:?_pragma=foreign_keys(on)")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
db.SetMaxOpenConns(1)
|
||||
if err := dictionary.BootstrapSchema(db); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
exec := func(q string, args ...any) {
|
||||
if _, err := db.Exec(q, args...); err != nil {
|
||||
b.Fatalf("seed: %s: %v", q, err)
|
||||
}
|
||||
}
|
||||
|
||||
exec("INSERT INTO meta (key, value) VALUES ('schema_version', '1')")
|
||||
exec("INSERT INTO meta (key, value) VALUES ('imported_at', '2025-01-01T00:00:00Z')")
|
||||
|
||||
poses := []string{"noun", "verb", "adjective", "adverb"}
|
||||
for i := 1; i <= 500; i++ {
|
||||
pos := poses[i%len(poses)]
|
||||
word := fmt.Sprintf("word%04d", i)
|
||||
exec("INSERT INTO words (id, word, lang, pos, frequency) VALUES (?, ?, 'en', ?, ?)",
|
||||
i, word, pos, i%100)
|
||||
exec("INSERT INTO definitions (word_id, pos, gloss, source, priority) VALUES (?, ?, ?, 'wordnet', 10)",
|
||||
i, pos, fmt.Sprintf("def of %s", word))
|
||||
exec("INSERT INTO synonyms (word_id, synonym, source) VALUES (?, ?, 'wordnet')",
|
||||
i, fmt.Sprintf("syn_%s", word))
|
||||
exec("INSERT INTO translations (word_id, translation, target_lang, source) VALUES (?, ?, 'fr', 'wiktionary')",
|
||||
i, fmt.Sprintf("fr_%s", word))
|
||||
}
|
||||
|
||||
dict := dictionary.NewFromDB(db)
|
||||
b.Cleanup(func() { db.Close() })
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("GET /valid", handleValid(dict))
|
||||
mux.HandleFunc("GET /random", handleRandom(dict))
|
||||
mux.HandleFunc("GET /define", handleDefine(dict))
|
||||
mux.HandleFunc("GET /synonyms", handleSynonyms(dict))
|
||||
mux.HandleFunc("GET /translate", handleTranslate(dict))
|
||||
mux.HandleFunc("GET /health", handleHealth(dict, ":memory:"))
|
||||
return mux
|
||||
}
|
||||
|
||||
func benchRequest(b *testing.B, mux *http.ServeMux, path string) {
|
||||
b.Helper()
|
||||
req := httptest.NewRequest("GET", path, nil)
|
||||
b.ResetTimer()
|
||||
for b.Loop() {
|
||||
w := httptest.NewRecorder()
|
||||
mux.ServeHTTP(w, req)
|
||||
if w.Code != 200 {
|
||||
b.Fatalf("status %d for %s", w.Code, path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHTTPValid(b *testing.B) {
|
||||
mux := setupBenchServer(b)
|
||||
benchRequest(b, mux, "/valid?word=word0003&lang=en")
|
||||
}
|
||||
|
||||
func BenchmarkHTTPRandom(b *testing.B) {
|
||||
mux := setupBenchServer(b)
|
||||
benchRequest(b, mux, "/random?lang=en")
|
||||
}
|
||||
|
||||
func BenchmarkHTTPRandomFiltered(b *testing.B) {
|
||||
mux := setupBenchServer(b)
|
||||
benchRequest(b, mux, "/random?lang=en&pos=noun&min=5&max=10")
|
||||
}
|
||||
|
||||
func BenchmarkHTTPDefine(b *testing.B) {
|
||||
mux := setupBenchServer(b)
|
||||
benchRequest(b, mux, "/define?word=word0003&lang=en")
|
||||
}
|
||||
|
||||
func BenchmarkHTTPSynonyms(b *testing.B) {
|
||||
mux := setupBenchServer(b)
|
||||
benchRequest(b, mux, "/synonyms?word=word0003&lang=en")
|
||||
}
|
||||
|
||||
func BenchmarkHTTPTranslate(b *testing.B) {
|
||||
mux := setupBenchServer(b)
|
||||
benchRequest(b, mux, "/translate?word=word0003&from=en&to=fr")
|
||||
}
|
||||
|
||||
func BenchmarkHTTPHealth(b *testing.B) {
|
||||
mux := setupBenchServer(b)
|
||||
benchRequest(b, mux, "/health")
|
||||
}
|
||||
Reference in New Issue
Block a user