package query
import (
"slices"
"testing"
"mimi/internal/provider/logseq"
)
const (
graphPath = "/home/user/code/clone/cvland"
)
func TestEval(t *testing.T) {
query2expected := map[string]int{
`<div class="query-results"><div class="query-results-header">Query: <code>(property :supply "next-month")</code></div><p><em>No results</em></p></div>`: 76,
`<div class="query-results"><div class="query-results-header">Query: <code>(page-property :wood-durability)</code></div><p><em>No results</em></p></div>`: 35,
`<div class="query-results"><div class="query-results-header">Query: <code>@master</code></div><p><em>No results</em></p></div>`: 7,
`<div class="query-results"><div class="query-results-header">Query: <code>(page-tags psycho)</code></div><p><em>No results</em></p></div>`: 5,
`<div class="query-results"><div class="query-results-header">Query: <code>(and (page-tags species) (not (page-tags class)) (and (page-tags supply)))</code></div><p><em>No results</em></p></div>`: 2,
`<div class="query-results"><div class="query-results-header">Query: <code>(and (page-tags genus))</code> (4 results)</div><ul>
<li><a href="/cybics/crystal/cinnamon" class="internal-link">cybics/crystal/cinnamon</a></li>
<li><a href="/cybics/crystal/curcuma" class="internal-link">cybics/crystal/curcuma</a></li>
<li><a href="/cybics/crystal/resin" class="internal-link">cybics/crystal/resin</a></li>
<li><a href="/cybics/crystal/taro" class="internal-link">cybics/crystal/taro</a></li>
</ul></div>`: 364,
`<div class="query-results"><div class="query-results-header">Query: <code>(and fern (page-tags species ))</code></div><p><em>No results</em></p></div>`: 14,
}
g := logseq.NewRegexGraph(graphPath)
for q, expected := range query2expected {
res, err := Eval(t.Context(), g, q)
if err != nil {
t.Errorf("failed to eval query '%s' with %s", q, err)
}
if len(res.Pages) != expected {
titles := make([]string, len(res.Pages))
for i, page := range res.Pages {
titles[i] = page.Title()
}
t.Errorf("got %d pages instead of %d for '%s', titles: %#v", len(res.Pages), expected, q, titles)
}
}
}
func TestEval_Fails(t *testing.T) {
before2expected := map[string]string{
`<div class="query-results"><div class="query-results-header">Query: <code>(and [] (page-tags species) (not (page-tags class)))</code> (16 results)</div><ul>
<li><a href="/cyber-valley/cve/land/chayote-harvest" class="internal-link">cyber-valley/cve/land/chayote harvest</a></li>
<li><a href="/cyber-valley/cve/land/propagate-plants" class="internal-link">cyber-valley/cve/land/propagate plants</a></li>
<li><a href="/cyber-valley/cve/ops/animal-care" class="internal-link">cyber-valley/cve/ops/animal care</a></li>
<li><a href="/cyber-valley/cve/ops/avocado-harvest" class="internal-link">cyber-valley/cve/ops/avocado harvest</a></li>
<li><a href="/cyber-valley/cve/ops/banana-harvest" class="internal-link">cyber-valley/cve/ops/banana harvest</a></li>
<li><a href="/cyber-valley/cve/ops/deworming-sheeps" class="internal-link">cyber-valley/cve/ops/deworming sheeps</a></li>
<li><a href="/cyber-valley/cve/ops/feeding-guideline" class="internal-link">cyber-valley/cve/ops/feeding guideline</a></li>
<li><a href="/cyber-valley/cve/ops/harvest-carrot" class="internal-link">cyber-valley/cve/ops/harvest carrot</a></li>
<li><a href="/cyber-valley/cve/ops/harvest-jackfruit" class="internal-link">cyber-valley/cve/ops/harvest jackfruit</a></li>
<li><a href="/cyber-valley/cve/ops/harvest-seeds" class="internal-link">cyber-valley/cve/ops/harvest seeds</a></li>
<li><a href="/cyberia/research/cyber-sheep/cyber-sheep" class="internal-link">cyberia/research/cyber-sheep/cyber-sheep</a></li>
<li><a href="/cybics/bio/mycelium" class="internal-link">cybics/bio/mycelium</a></li>
<li><a href="/cybics/chemo/curcuma" class="internal-link">cybics/chemo/curcuma</a></li>
<li><a href="/cybics/crystal/daun-salam" class="internal-link">cybics/crystal/daun salam</a></li>
<li><a href="/cybics/crystal/forest" class="internal-link">cybics/crystal/forest</a></li>
<li><a href="/cybics/crystal/pseudomonas-aeruginosa" class="internal-link">cybics/crystal/pseudomonas aeruginosa</a></li>
</ul></div>`: `failed to evaluate state with failed to evaluate 'and' with unexpected string atom '[]'`,
}
g := logseq.NewRegexGraph(graphPath)
for before, expected := range before2expected {
_, err := Eval(t.Context(), g, before)
if err == nil || err.Error() != expected {
t.Errorf("query '%s' should fail with '%s' but failed with '%s'", before, expected, err)
}
}
}
func TestParsing_RawEDN(t *testing.T) {
queries := []string{
`<div class="query-results"><div class="query-results-header">Query: <code>(page-property :wood-durability)</code></div><p><em>No results</em></p></div>`,
`<div class="query-results"><div class="query-results-header">Query: <code>@master</code></div><p><em>No results</em></p></div>`,
`<div class="query-results"><div class="query-results-header">Query: <code>(page-tags psycho)</code></div><p><em>No results</em></p></div>`,
`<div class="query-results"><div class="query-results-header">Query: <code>(and [] (page-tags species) (not (page-tags class)))</code> (16 results)</div><ul>
<li><a href="/cyber-valley/cve/land/chayote-harvest" class="internal-link">cyber-valley/cve/land/chayote harvest</a></li>
<li><a href="/cyber-valley/cve/land/propagate-plants" class="internal-link">cyber-valley/cve/land/propagate plants</a></li>
<li><a href="/cyber-valley/cve/ops/animal-care" class="internal-link">cyber-valley/cve/ops/animal care</a></li>
<li><a href="/cyber-valley/cve/ops/avocado-harvest" class="internal-link">cyber-valley/cve/ops/avocado harvest</a></li>
<li><a href="/cyber-valley/cve/ops/banana-harvest" class="internal-link">cyber-valley/cve/ops/banana harvest</a></li>
<li><a href="/cyber-valley/cve/ops/deworming-sheeps" class="internal-link">cyber-valley/cve/ops/deworming sheeps</a></li>
<li><a href="/cyber-valley/cve/ops/feeding-guideline" class="internal-link">cyber-valley/cve/ops/feeding guideline</a></li>
<li><a href="/cyber-valley/cve/ops/harvest-carrot" class="internal-link">cyber-valley/cve/ops/harvest carrot</a></li>
<li><a href="/cyber-valley/cve/ops/harvest-jackfruit" class="internal-link">cyber-valley/cve/ops/harvest jackfruit</a></li>
<li><a href="/cyber-valley/cve/ops/harvest-seeds" class="internal-link">cyber-valley/cve/ops/harvest seeds</a></li>
<li><a href="/cyberia/research/cyber-sheep/cyber-sheep" class="internal-link">cyberia/research/cyber-sheep/cyber-sheep</a></li>
<li><a href="/cybics/bio/mycelium" class="internal-link">cybics/bio/mycelium</a></li>
<li><a href="/cybics/chemo/curcuma" class="internal-link">cybics/chemo/curcuma</a></li>
<li><a href="/cybics/crystal/daun-salam" class="internal-link">cybics/crystal/daun salam</a></li>
<li><a href="/cybics/crystal/forest" class="internal-link">cybics/crystal/forest</a></li>
<li><a href="/cybics/crystal/pseudomonas-aeruginosa" class="internal-link">cybics/crystal/pseudomonas aeruginosa</a></li>
</ul></div>`,
`<div class="query-results"><div class="query-results-header">Query: <code>(and (property :supply "next-month") (property :project "edible oils"))</code></div><p><em>No results</em></p></div>`,
`<div class="query-results"><div class="query-results-header">Query: <code>(and conifer (and) (page-tags genus))</code></div><p><em>No results</em></p></div>`,
`<div class="query-results"><div class="query-results-header">Query: <code>(and (page-tags genus) (not (page-tags class)) (not (page-tags research)) (not (page-tags prohibited)))</code> (4 results)</div><ul>
<li><a href="/cybics/crystal/cinnamon" class="internal-link">cybics/crystal/cinnamon</a></li>
<li><a href="/cybics/crystal/curcuma" class="internal-link">cybics/crystal/curcuma</a></li>
<li><a href="/cybics/crystal/resin" class="internal-link">cybics/crystal/resin</a></li>
<li><a href="/cybics/crystal/taro" class="internal-link">cybics/crystal/taro</a></li>
</ul></div>`,
`<div class="query-results"><div class="query-results-header">Query: <code>(page-property :type "sector")</code></div><p><em>No results</em></p></div>`,
}
for _, q := range queries {
_, err := parseQuery(q)
if err != nil {
t.Errorf("failed query %s with %s", q, err)
}
}
}
func TestParsing_Options(t *testing.T) {
query2expected := map[string]QueryOptions{
`<div class="query-results"><div class="query-results-header">Query: <code>(page-tags super)</code></div><p><em>No results</em></p></div>
query-properties:: [:page :tags :alias]
query-sort-by:: page
query-sort-desc:: true`: QueryOptions{
properties: []string{"page", "tags", "alias"},
sortBy: "page",
sortDesc: true,
},
}
for query, expected := range query2expected {
got, err := parseQuery(query)
if err != nil {
t.Errorf("failed to parse query %s with %s", query, err)
}
if got.opts.sortBy != expected.sortBy {
goto testFailed
}
if got.opts.sortDesc != expected.sortDesc {
goto testFailed
}
if !slices.Equal(got.opts.properties, expected.properties) {
goto testFailed
}
continue
testFailed:
t.Errorf("got %#v, expected %#v", got, expected)
}
}
func TestBuildTable(t *testing.T) {
pages := [][]logseq.Page{
[]logseq.Page{
logseq.Page{
Path: "foo.md",
Info: logseq.PageInfo{
Props: []logseq.Property{
logseq.Property{
Name: "tags",
Values: []string{"1", "2", "3"},
Level: logseq.PageLevel,
},
logseq.Property{
Name: "alias",
Values: []string{"bar"},
Level: logseq.PageLevel,
},
},
Refs: []string{},
},
},
logseq.Page{
Path: "bar.md",
Info: logseq.PageInfo{
Props: []logseq.Property{
logseq.Property{
Name: "tags",
Values: []string{"baz", "huz"},
Level: logseq.PageLevel,
},
},
Refs: []string{},
},
},
},
[]logseq.Page{
logseq.Page{Path: "foo.md"},
logseq.Page{Path: "bar.md"},
logseq.Page{Path: "buz.md"},
},
}
opts := []QueryOptions{
QueryOptions{
properties: []string{"page", "tags", "alias"},
sortBy: "alias",
sortDesc: true,
},
QueryOptions{
properties: []string{"page"},
sortBy: "page",
sortDesc: false,
},
}
expected := [][][]string{
[][]string{
[]string{"page", "tags", "alias"},
[]string{"foo", "1, 2, 3", "bar"},
[]string{"bar", "baz, huz", ""},
},
[][]string{
[]string{"page"},
[]string{"bar"},
[]string{"buz"},
[]string{"foo"},
},
}
if len(pages) != len(opts) || len(opts) != len(expected) {
t.Errorf("wrong test setup")
}
for i := 0; i < len(pages); i++ {
t.Logf("Checking %#v", opts[i])
table := buildTable(pages[i], opts[i])
if slices.EqualFunc(table, expected[i], slices.Equal) {
continue
}
t.Errorf("expected %#v, got %#v", expected[i], table)
}
}