#!/bin/zsh -f

setopt extendedglob badpattern
unsetopt kshglob

failed=0
while read res str pat; do
  [[ $res = '#' ]] && continue
  [[ $str = ${~pat} ]]
  ts=$?
  [[ $1 = -q ]] || print "$ts:  [[ $str = $pat ]]"
  if [[ ( $ts -gt 0 && $res = t) || ($ts -eq 0 && $res = f) ]]; then
    print "Test failed:  [[ $str = $pat ]]"
    (( failed++ ))
  fi
done <<EOT
# a few simple things certain nameless idiots have been known to mess up
t foo~                foo~
t foo~                (foo~)
t foo~                (foo~|)
t foo.c               *.c~boo*
f foo.c               *.c~boo*~foo*
# closures
t fofo                (fo#)#
t ffo                 (fo#)#
t foooofo             (fo#)#
t foooofof            (fo#)#
t fooofoofofooo       (fo#)#
f foooofof            (fo##)#
f xfoooofof           (fo#)#
f foooofofx           (fo#)#
t ofxoofxo            ((ofo#x)#o)#
f ofooofoofofooo      (fo#)#
t foooxfooxfoxfooox   (fo#x)#
f foooxfooxofoxfooox  (fo#x)#
t foooxfooxfxfooox    (fo#x)#
t ofxoofxo            ((ofo#x)#o)#
t ofoooxoofxo         ((ofo#x)#o)#
t ofoooxoofxoofoooxoofxo            ((ofo#x)#o)#
t ofoooxoofxoofoooxoofxoo           ((ofo#x)#o)#
f ofoooxoofxoofoooxoofxofo          ((ofo#x)#o)#
t ofoooxoofxoofoooxoofxooofxofxo    ((ofo#x)#o)#
t aac    ((a))#a(c)
t ac     ((a))#a(c)
f c      ((a))#a(c)
t aaac   ((a))#a(c)
f baaac  ((a))#a(c)
t abcd   ?(a|b)c#d
t abcd   (ab|ab#)c#d
t acd    (ab|ab#)c#d
t abbcd  (ab|ab#)c#d
t effgz  (bc##d|ef#g?|(h|)i(j|k))
t efgz   (bc##d|ef#g?|(h|)i(j|k))
t egz    (bc##d|ef#g?|(h|)i(j|k))
t egzefffgzbcdij    (bc##d|ef#g?|(h|)i(j|k))#
f egz    (bc##d|ef##g?|(h|)i(j|k))
t ofoofo (ofo##)#
t oxfoxoxfox    (oxf(ox)##)#
f oxfoxfox      (oxf(ox)##)#
t ofoofo        (ofo##|f)#
# The following is supposed to match only as fo+ofo+ofo
t foofoofo      (foo|f|fo)(f|ofo##)#
t oofooofo      (of|oofo##)#
t fffooofoooooffoofffooofff     (f#o#)#
# If the following is really slow, that's a bug.
f fffooofoooooffoofffooofffx     (f#o#)#
# The following tests backtracking in alternation matches
t fofoofoofofoo (fo|foo)#
# Exclusion: test both types
t foo           ((^x))
t foo           ((^x)*)
f foo           ((^foo))
t foo           ((^foo)*)
t foobar        ((^foo))
t foobar        ((^foo)*)
f foot          z*~*x
t zoot          z*~*x
f foox          z*~*x
f zoox          z*~*x
t moo.cow       (*~*.*).(*~*.*)
f mad.moo.cow   (*~*.*).(*~*.*)
t moo.cow       (^*.*).(^*.*)
f sane.moo.cow  (^*.*).(^*.*)
f mucca.pazza   mu(^c#)?.pa(^z#)?
f _foo~         _(|*[^~])
t fff           ((^f))
t fff           ((^f)#)
t fff           ((^f)##)
t ooo           ((^f))
t ooo           ((^f)#)
t ooo           ((^f)##)
t foo           ((^f))
t foo           ((^f)#)
t foo           ((^f)##)
f f             ((^f))
f f             ((^f)#)
f f             ((^f)##)
t foot          (^z*|*x)
f zoot          (^z*|*x)
t foox          (^z*|*x)
t zoox          (^z*|*x)
t foo           (^foo)#
f foob          (^foo)b*
t foobb         (^foo)b*
f foob          (*~foo)b*
t foobb         (*~foo)b*
f zsh           ^z*
t a%1X          [[:alpha:][:punct:]]#[[:digit:]][^[:lower:]]
f a%1           [[:alpha:][:punct:]]#[[:digit:]][^[:lower:]]
t [:            [[:]#
t :]            []:]#
t :]            [:]]#
t [             [[]
t ]             []]
t []            [^]]]
# Case insensitive matching
t fooxx         (#i)FOOXX
f fooxx         (#l)FOOXX
t FOOXX         (#l)fooxx
f fooxx         (#i)FOO(#I)X(#i)X
t fooXx         (#i)FOO(#I)X(#i)X
t fooxx         ((#i)FOOX)x
f fooxx         ((#i)FOOX)X
f BAR           (bar|(#i)foo)
t FOO           (bar|(#i)foo)
t Modules       (#i)*m*
t fooGRUD       (#i)(bar|(#I)foo|(#i)rod)grud
f FOOGRUD       (#i)(bar|(#I)foo|(#i)rod)grud
t readme        (#i)readme~README|readme
# the readme doesn't get excluded the second time...
t readme        (#i)readme~README|readme~README
# Ranges with backtracking
t 633           <1-1000>33
t 633           <-1000>33
t 633           <1->33
t 633           <->33
# An open top end of a range will match any integer, even
# if not representable in the internal integer type.
t 12345678901234567890123456789012345678901234567890123456789012345678901234567890foo <42->foo
# Approximate matching
t READ.ME       (#ia1)readme
f READ..ME      (#ia1)readme
t README        (#ia1)readm
t READM         (#ia1)readme
t README        (#ia1)eadme
t EADME         (#ia1)readme
t READEM        (#ia1)readme
f ADME          (#ia1)readme
f README        (#ia1)read
t bob           (#a1)[b][b]
f bob           (#a1)[b][b]a
t bob           (#a1)[b]o[b]a
f bob           (#a1)[c]o[b]
t abcd          (#a2)XbcX
t abcd          (#a2)ad
t ad            (#a2)abcd
t abcd          (#a2)bd
t bd            (#a2)abcd
t badc          (#a2)abcd
# This next one is a little tricky: a[d]bc[] = a[]bc[d]
t adbc          (#a2)abcd
f dcba          (#a2)abcd
# the next one is [d][cb][a] = [a][bc][d] with a transposition
t dcba          (#a3)abcd
t aabaXaaabY    (#a1)(a#b)#Y
t aabaXaaabY    (#a1)(a#b)(a#b)Y
t aaXaaaaabY    (#a1)(a#b)(a#b)Y
t aaaXaaabY     (#a1)(a##b)##Y
t aaaXbaabY     (#a1)(a##b)##Y
f read.me       (#ia1)README~READ.ME
t read.me       (#ia1)README~READ_ME
f read.me       (#ia1)README~(#a1)READ_ME
t test          *((#s)|/)test((#e)|/)*
t test/path     *((#s)|/)test((#e)|/)*
t path/test     *((#s)|/)test((#e)|/)*
t path/test/ohyes *((#s)|/)test((#e)|/)*
f atest         *((#s)|/)test((#e)|/)*
f testy         *((#s)|/)test((#e)|/)*
f testy/path    *((#s)|/)test((#e)|/)*
f path/atest    *((#s)|/)test((#e)|/)*
f atest/path    *((#s)|/)test((#e)|/)*
f path/testy    *((#s)|/)test((#e)|/)*
f path/testy/ohyes *((#s)|/)test((#e)|/)*
f path/atest/ohyes *((#s)|/)test((#e)|/)*
t XabcdabcY        X(ab|c|d)(#c5)Y
t XabcdabcY        X(ab|c|d)(#c1,5)Y
t XabcdabcY        X(ab|c|d)(#c5,8)Y
t XabcdabcY        X(ab|c|d)(#c4,)Y
f XabcdabcY        X(ab|c|d)(#c6,)Y
f XabcdabcY        X(ab|c|d)(#c1,4)Y
t ZX               Z(|)(#c1)X
t froofroo         (fro(#c2))(#c2)
f froofroofroo     (fro(#c2))(#c2)
f froofro          (fro(#c2))(#c2)
t ax               ?(#c1,2)x
t ax               ?(#c1,)x
t ax               ?(#c0,1)x
f ax               ?(#c0,0)x
f ax               ?(#c2,)x
t aa               a(#c1,2)a
t aa               a(#c1,)a
t aa               a(#c0,1)a
f aa               a(#c0,0)a
f aa               a(#c2,)a
t test.zsh         *.?(#c1)sh
t test.bash        *.?(#c2)sh
t test.bash        *.?(#c1,2)sh
t test.bash        *.?(#c1,)sh
t test.zsh         *.?(#c1,)sh
EOT
print "$failed tests failed."
