Skip to content

Commit

Permalink
update new test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
zhengchun committed Mar 25, 2024
1 parent 70e7f92 commit ae2b67d
Show file tree
Hide file tree
Showing 6 changed files with 675 additions and 1,037 deletions.
68 changes: 68 additions & 0 deletions xpath_axes_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package xpath

import "testing"

func Test_self(t *testing.T) {
test_xpath_elements(t, employee_example, `//name/self::*`, 4, 9, 14)
}

func Test_child(t *testing.T) {
test_xpath_elements(t, employee_example, `/empinfo/child::*`, 3, 8, 13)
test_xpath_elements(t, employee_example, `/empinfo/child::node()`, 3, 8, 13)
test_xpath_values(t, employee_example, `//name/child::text()`, "Opal Kole", "Max Miller", "Beccaa Moss")
test_xpath_elements(t, employee_example, `//child::employee/child::email`, 6, 11, 16)
}

func Test_descendant(t *testing.T) {
test_xpath_elements(t, employee_example, `//employee/descendant::*`, 4, 5, 6, 9, 10, 11, 14, 15, 16)
test_xpath_count(t, employee_example, `//descendant::employee`, 3)
}

func Test_descendant_or_self(t *testing.T) {
test_xpath_tags(t, employee_example.FirstChild, `self::*`, "empinfo")
test_xpath_elements(t, employee_example, `//employee/descendant-or-self::*`, 3, 4, 5, 6, 8, 9, 10, 11, 13, 14, 15, 16)
test_xpath_count(t, employee_example, `//descendant-or-self::employee`, 3)
}

func Test_ancestor(t *testing.T) {
test_xpath_tags(t, employee_example, `//employee/ancestor::*`, "empinfo") //
test_xpath_elements(t, employee_example, `//ancestor::name`, 4, 9, 14)
}

func Test_ancestor_or_self(t *testing.T) {
test_xpath_elements(t, employee_example, `//employee/ancestor-or-self::*`, 2, 3, 8, 13)
test_xpath_elements(t, employee_example, `//name/ancestor-or-self::employee`, 2, 3, 8, 13)
}

func Test_parent(t *testing.T) {
test_xpath_elements(t, employee_example, `//name/parent::*`, 3, 8, 13)
test_xpath_elements(t, employee_example, `//name/parent::employee`, 3, 8, 13)
}

func Test_attribute(t *testing.T) {
test_xpath_values(t, employee_example, `//attribute::id`, "1", "2", "3")
test_xpath_tags(t, employee_example, `//attribute::*`, "id", "discipline", "experience", "id", "from", "discipline", "experience", "id", "discipline")
}

func Test_following(t *testing.T) {
test_xpath_elements(t, employee_example, `//employee[@id=1]/following::*`, 8, 9, 10, 11, 13, 14, 15, 16)
}

func Test_following_sibling(t *testing.T) {
test_xpath_elements(t, employee_example, `//employee[@id=1]/following-sibling::*`, 8, 13)
test_xpath_elements(t, employee_example, `//employee[@id=1]/following-sibling::employee`, 8, 13)
}

func Test_preceding(t *testing.T) {
//testXPath3(t, html, "//li[last()]/preceding-sibling::*[2]", selectNode(html, "//li[position()=2]"))
//testXPath3(t, html, "//li/preceding::*[1]", selectNode(html, "//h1"))
test_xpath_elements(t, employee_example, `//employee[@id=3]/preceding::*`, 8, 9, 10, 11, 3, 4, 5, 6)
}

func Test_preceding_sibling(t *testing.T) {
test_xpath_elements(t, employee_example, `//employee[@id=3]/preceding-sibling::*`, 8, 3)
}

func Test_namespace(t *testing.T) {
// TODO
}
55 changes: 55 additions & 0 deletions xpath_expression_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package xpath

import (
"testing"
)

// `*/employee` [Not supported]

func TestRelativePaths(t *testing.T) {
test_xpath_elements(t, book_example, `//book`, 3, 9, 15, 25)
test_xpath_elements(t, book_example, `//bookstore/book`, 3, 9, 15, 25)
test_xpath_tags(t, book_example, `//book/..`, "bookstore")
test_xpath_elements(t, book_example, `//book[@category="cooking"]/..`, 2)
test_xpath_elements(t, book_example, `//book/year[text() = 2005]/../..`, 2) // bookstore
test_xpath_elements(t, book_example, `//book/year/../following-sibling::*`, 9, 15, 25)
test_xpath_count(t, book_example, `//bookstore/book/*`, 20)
test_xpath_tags(t, html_example, "//title/../..", "html")
test_xpath_elements(t, html_example, "//ul/../p", 19)
}

func TestAbsolutePaths(t *testing.T) {
test_xpath_elements(t, book_example, `bookstore`, 2)
test_xpath_elements(t, book_example, `bookstore/book`, 3, 9, 15, 25)
test_xpath_elements(t, book_example, `(bookstore/book)`, 3, 9, 15, 25)
test_xpath_elements(t, book_example, `bookstore/book[2]`, 9)
test_xpath_elements(t, book_example, `bookstore/book[last()]`, 25)
test_xpath_elements(t, book_example, `bookstore/book[last()]/title`, 26)
test_xpath_values(t, book_example, `/bookstore/book[last()]/title/text()`, "Learning XML")
test_xpath_values(t, book_example, `/bookstore/book[@category = "children"]/year`, "2005")
test_xpath_elements(t, book_example, `bookstore/book/..`, 2)
test_xpath_elements(t, book_example, `/bookstore/*`, 3, 9, 15, 25)
test_xpath_elements(t, book_example, `/bookstore/*/title`, 4, 10, 16, 26)
}

func TestAttributes(t *testing.T) {
test_xpath_tags(t, html_example.FirstChild, "@*", "lang")
test_xpath_tags(t, employee_example, `//@*`, "id", "discipline", "experience", "id", "from", "discipline", "experience", "id", "discipline")
test_xpath_values(t, employee_example, `//@discipline`, "web", "DBA", "appdev")
test_xpath_count(t, employee_example, `//employee/@id`, 3)
}

func TestExpressions(t *testing.T) {
test_xpath_elements(t, book_example, `//book[@category = "cooking"] | //book[@category = "children"]`, 3, 9)
test_xpath_count(t, html_example, `//ul/*`, 3)
test_xpath_count(t, html_example, `//ul/*/a`, 3)
// Sequence
//
// table/tbody/tr/td/(para, .[not(para)], ..)
}

func TestSequence(t *testing.T) {
// `//table/tbody/tr/td/(para, .[not(para)],..)`
test_xpath_count(t, html_example, `//body/(h1, h2, p)`, 2)
test_xpath_count(t, html_example, `//body/(h1, h2, p, ..)`, 3)
}
212 changes: 212 additions & 0 deletions xpath_function_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
package xpath

import (
"math"
"testing"
)

// Some test examples from http://zvon.org/comp/r/ref-XPath_2.html

func Test_func_boolean(t *testing.T) {
test_xpath_eval(t, empty_example, `true()`, true)
test_xpath_eval(t, empty_example, `false()`, false)
test_xpath_eval(t, empty_example, `boolean(0)`, false)
test_xpath_eval(t, empty_example, `boolean(1)`, true)
test_xpath_eval(t, empty_example, `boolean(2)`, true)
test_xpath_eval(t, empty_example, `boolean(true)`, false)
test_xpath_eval(t, empty_example, `boolean(1 > 2)`, false)
test_xpath_eval(t, book_example, `boolean(//*[@lang])`, true)
test_xpath_eval(t, book_example, `boolean(//*[@x])`, false)
}

func Test_func_name(t *testing.T) {
test_xpath_eval(t, html_example, `name(//html/@lang)`, "lang")
test_xpath_eval(t, html_example, `name(html/head/title)`, "title")
test_xpath_count(t, html_example, `//*[name() = "li"]`, 3)
}

func Test_func_not(t *testing.T) {
//test_xpath_eval(t, empty_example, `not(0)`, true)
//test_xpath_eval(t, empty_example, `not(1)`, false)
test_xpath_elements(t, employee_example, `//employee[not(@id = "1")]`, 8, 13)
test_xpath_elements(t, book_example, `//book[not(year = 2005)]`, 15, 25)
test_xpath_count(t, book_example, `//book[not(title)]`, 0)
}

func Test_func_ceiling_floor(t *testing.T) {
test_xpath_eval(t, empty_example, "ceiling(5.2)", float64(6))
test_xpath_eval(t, empty_example, "floor(5.2)", float64(5))
}

func Test_func_concat(t *testing.T) {
test_xpath_eval(t, empty_example, `concat("1", "2", "3")`, "123")
//test_xpath_eval(t, empty_example, `concat("Ciao!", ())`, "Ciao!")
test_xpath_eval(t, book_example, `concat(//book[1]/title, ", ", //book[1]/year)`, "Everyday Italian, 2005")
}

func Test_func_contains(t *testing.T) {
test_xpath_eval(t, empty_example, `contains("tattoo", "t")`, true)
test_xpath_eval(t, empty_example, `contains("tattoo", "T")`, false)
test_xpath_eval(t, empty_example, `contains("tattoo", "ttt")`, false)
//test_xpath_eval(t, empty_example, `contains("", ())`, true)
test_xpath_elements(t, book_example, `//book[contains(title, "Potter")]`, 9)
test_xpath_elements(t, book_example, `//book[contains(year, "2005")]`, 3, 9)
assertPanic(t, func() { selectNode(html_example, "//*[contains(0, 0)]") })
}

func Test_func_count(t *testing.T) {
test_xpath_eval(t, book_example, `count(//book)`, float64(4))
test_xpath_eval(t, book_example, `count(//book[3]/author)`, float64(5))
}

func Test_func_ends_with(t *testing.T) {
test_xpath_eval(t, empty_example, `ends-with("tattoo", "tattoo")`, true)
test_xpath_eval(t, empty_example, `ends-with("tattoo", "atto")`, false)
test_xpath_elements(t, book_example, `//book[ends-with(@category,'ing')]`, 3)
test_xpath_elements(t, book_example, `//book[ends-with(./price,'.99')]`, 9, 15)
assertPanic(t, func() { selectNode(html_example, `//*[ends-with(0, 0)]`) }) // arg must be start with string
assertPanic(t, func() { selectNode(html_example, `//*[ends-with(name(), 0)]`) })
}

func Test_func_last(t *testing.T) {
test_xpath_elements(t, book_example, `//bookstore[last()]`, 2)
test_xpath_elements(t, book_example, `//bookstore/book[last()]`, 25)
test_xpath_elements(t, html_example, `//ul/li[last()]`, 15)
test_xpath_elements(t, html_example, `(//ul/li)[last()]`, 15)
}

func Test_func_local_name(t *testing.T) {
// TODO
}

func Test_func_starts_with(t *testing.T) {
test_xpath_eval(t, employee_example, `starts-with("tattoo", "tat")`, true)
test_xpath_eval(t, employee_example, `starts-with("tattoo", "att")`, false)
test_xpath_elements(t, book_example, `//book[starts-with(title,'Everyday')]`, 3)
assertPanic(t, func() { selectNode(html_example, `//*[starts-with(0, 0)]`) })
assertPanic(t, func() { selectNode(html_example, `//*[starts-with(name(), 0)]`) })
}

func Test_func_string(t *testing.T) {
test_xpath_eval(t, empty_example, `string(1.23)`, "1.23")
test_xpath_eval(t, empty_example, `string(3)`, "3")
}

func Test_func_string_join(t *testing.T) {
//test_xpath_eval(t, empty_example, `string-join(('Now', 'is', 'the', 'time', '...'), '')`, "Now is the time ...")
test_xpath_eval(t, empty_example, `string-join("some text", ";")`, "some text")
test_xpath_eval(t, book_example, `string-join(//book/@category, ";")`, "cooking;children;web;web")
}

func Test_func_string_length(t *testing.T) {
test_xpath_eval(t, empty_example, `string-length("Harp not on that string, madam; that is past.")`, float64(45))
test_xpath_eval(t, empty_example, `string-length(normalize-space(' abc '))`, float64(3))
test_xpath_eval(t, html_example, `string-length(//title/text())`, float64(len("My page")))
test_xpath_eval(t, html_example, `string-length(//html/@lang)`, float64(len("en")))
test_xpath_count(t, employee_example, `//employee[string-length(@id) > 0]`, 3) // = //employee[@id]
}

func Test_func_substring(t *testing.T) {
test_xpath_eval(t, empty_example, `substring("motor car", 6)`, " car")
test_xpath_eval(t, empty_example, `substring("metadata", 4, 3)`, "ada")
//test_xpath_eval(t, empty_example, `substring("12345", 5, -3)`, "") ?? it should be 1 ??
//test_xpath_eval(t, empty_example, `substring("12345", 1.5, 2.6)`, "234")
//test_xpath_eval(t, empty_example, `substring("12345", 0, 3)`, "12") // panic??
//test_xpath_eval(t, empty_example, `substring("12345", 5, -3)`, "1")
test_xpath_eval(t, html_example, `substring(//title/child::node(), 1)`, "My page")
}

func Test_func_substring_after(t *testing.T) {
test_xpath_eval(t, empty_example, `substring-after("tattoo", "tat")`, "too")
test_xpath_eval(t, empty_example, `substring-after("tattoo", "tattoo")`, "")
}

func Test_func_substring_before(t *testing.T) {
test_xpath_eval(t, empty_example, `substring-before("tattoo", "attoo")`, "t")
test_xpath_eval(t, empty_example, `substring-before("tattoo", "tatto")`, "")
}

func Test_func_sum(t *testing.T) {
test_xpath_eval(t, empty_example, `sum(1 + 2)`, float64(3))
test_xpath_eval(t, empty_example, `sum(1.1 + 2)`, float64(3.1))
test_xpath_eval(t, book_example, `sum(//book/price)`, float64(149.93))
assertPanic(t, func() { selectNode(html_example, `//title[sum('Hello') = 0]`) })
}

func Test_func_translate(t *testing.T) {
test_xpath_eval(t, empty_example, `translate("bar","abc","ABC")`, "BAr")
test_xpath_eval(t, empty_example, `translate("--aaa--","abc-","ABC")`, "AAA")
test_xpath_eval(t, empty_example, `translate("abcdabc", "abc", "AB")`, "ABdAB")
test_xpath_eval(t, empty_example, `translate('The quick brown fox', 'brown', 'red')`, "The quick red fdx")
}

func Test_func_matches(t *testing.T) {
test_xpath_eval(t, empty_example, `matches("abracadabra", "bra")`, true)
test_xpath_eval(t, empty_example, `matches("abracadabra", "(?i)^A.*A$")`, true)
test_xpath_eval(t, empty_example, `matches("abracadabra", "^a.*a$")`, true)
test_xpath_eval(t, empty_example, `matches("abracadabra", "^bra")`, false)
assertPanic(t, func() { selectNode(html_example, `//*[matches()]`) }) // arg len check failure
assertPanic(t, func() { selectNode(html_example, "//*[matches(substring(), 0)]") }) // first arg processing failure
assertPanic(t, func() { selectNode(html_example, "//*[matches(@href, substring())]") }) // second arg processing failure
assertPanic(t, func() { selectNode(html_example, "//*[matches(@href, 0)]") }) // second arg not string
assertPanic(t, func() { selectNode(html_example, "//*[matches(@href, '[invalid')]") }) // second arg invalid regexp
// testing unexpected the regular expression.
_, err := Compile(`//*[matches(., '^[\u0621-\u064AA-Za-z\-]+')]`)
assertErr(t, err)
_, err = Compile(`//*[matches(., '//*[matches(., '\w+`)
assertErr(t, err)
}

func Test_func_number(t *testing.T) {
test_xpath_eval(t, empty_example, `number(10)`, float64(10))
test_xpath_eval(t, empty_example, `number(1.11)`, float64(1.11))
test_xpath_eval(t, empty_example, `number("10") > 10`, false)
test_xpath_eval(t, empty_example, `number("10") = 10`, true)
test_xpath_eval(t, empty_example, `number("123") < 1000`, true)
assertTrue(t, math.IsNaN(MustCompile(`number("123a")`).Evaluate(createNavigator(empty_example)).(float64)))
}

func Test_func_position(t *testing.T) {
test_xpath_elements(t, book_example, `//book[position() = 1]`, 3)
//test_xpath_elements(t, book_example, `//book[(position() mod 2) = 0]`, 9, 25)
//test_xpath_elements(t, book_example, `//book[position() = last()]`, 25)
//test_xpath_elements(t, book_example, `//book/*[position() = 1]`, 4, 10, 16, 26)
test_xpath_elements(t, book_example, `(//book/title)[position() = 1]`, 3)
}

func Test_func_replace(t *testing.T) {
test_xpath_eval(t, empty_example, `replace('aa-bb-cc','bb','ee')`, "aa-ee-cc")
test_xpath_eval(t, empty_example, `replace("abracadabra", "bra", "*")`, "a*cada*")
test_xpath_eval(t, empty_example, `replace("abracadabra", "a", "")`, "brcdbr")
// The below xpath expressions is not supported yet
//
//test_xpath_eval(t, empty_example, `replace("abracadabra", "a.*a", "*")`, "*")
//test_xpath_eval(t, empty_example, `replace("abracadabra", "a.*?a", "*")`, "*c*bra")
//test_xpath_eval(t, empty_example, `replace("abracadabra", ".*?", "$1")`, "*c*bra") // error, because the pattern matches the zero-length string
//test_xpath_eval(t, empty_example, `replace("AAAA", "A+", "b")`, "b")
//test_xpath_eval(t, empty_example, `replace("AAAA", "A+?", "b")`, "bbb")
//test_xpath_eval(t, empty_example, `replace("darted", "^(.*?)d(.*)$", "$1c$2")`, "carted")
//test_xpath_eval(t, empty_example, `replace("abracadabra", "a(.)", "a$1$1")`, "abbraccaddabbra")
}

func Test_func_reverse(t *testing.T) {
//test_xpath_eval(t, employee_example, `reverse(("hello"))`, "hello") // Not passed
test_xpath_elements(t, employee_example, `reverse(//employee)`, 13, 8, 3)
test_xpath_elements(t, employee_example, `//employee[reverse(.) = reverse(.)]`, 3, 8, 13)
assertPanic(t, func() { selectNode(html_example, "reverse(concat())") }) // invalid node-sets argument.
assertPanic(t, func() { selectNode(html_example, "reverse()") }) // missing node-sets argument.
}

func Test_func_round(t *testing.T) {
test_xpath_eval(t, employee_example, `round(2.5)`, 3) // int
test_xpath_eval(t, employee_example, `round(2.5)`, 3)
test_xpath_eval(t, employee_example, `round(2.4999)`, 2)
}

func Test_func_namespace_uri(t *testing.T) {
// TODO
}

func Test_func_normalize_space(t *testing.T) {
// TODO
}
Loading

0 comments on commit ae2b67d

Please sign in to comment.