aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/test/lux/data/format/xml.lux
blob: e0a1a5c05765ae94416a55099759e0b761d0ee69 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
(.module:
  [lux (#- char)
   ["%" data/text/format (#+ format)]
   ["_" test (#+ Test)]
   [abstract
    [monad (#+ Monad do)]
    {[0 #spec]
     [/
      ["$." equivalence]
      ["$." codec]]}]
   [control
    pipe
    ["E" try]
    ["p" parser
     ["</>" xml]]]
   [data
    ["." name]
    ["." maybe]
    ["." text ("#@." equivalence)]
    [number
     ["n" nat]]
    [collection
     ["." dictionary]
     ["." list ("#@." functor)]]]
   [math
    ["r" random (#+ Random) ("#@." monad)]]]
  {1
   ["." / (#+ XML)]})

(def: char-range
  Text
  (format "_"
          "abcdefghijklmnopqrstuvwxyz"
          "ABCDEFGHIJKLMNOPQRSTUVWXYZ"))

(def: char
  (Random Nat)
  (do {! r.monad}
    [idx (|> r.nat (:: ! map (n.% (text.size char-range))))]
    (wrap (maybe.assume (text.nth idx char-range)))))

(def: (size bottom top)
  (-> Nat Nat (Random Nat))
  (let [constraint (|>> (n.% top) (n.max bottom))]
    (r@map constraint r.nat)))

(def: (text bottom top)
  (-> Nat Nat (Random Text))
  (do r.monad
    [size (..size bottom top)]
    (r.text ..char size)))

(def: xml-identifier^
  (Random Name)
  (r.and (..text 0 10)
         (..text 1 10)))

(def: #export xml
  (Random XML)
  (r.rec (function (_ xml)
           (r.or (..text 1 10)
                 (do r.monad
                   [size (..size 0 2)]
                   ($_ r.and
                       xml-identifier^
                       (r.dictionary name.hash size xml-identifier^ (..text 0 10))
                       (r.list size xml)))))))

(def: #export test
  Test
  (<| (_.context (%.name (name-of /.XML)))
      ($_ _.and
          ($equivalence.spec /.equivalence ..xml)
          ($codec.spec /.equivalence /.codec ..xml)

          (do {! r.monad}
            [text (..text 1 10)
             num-children (|> r.nat (:: ! map (n.% 5)))
             children (r.list num-children (..text 1 10))
             tag xml-identifier^
             attribute xml-identifier^
             value (..text 1 10)
             #let [node (#/.Node tag
                                 (dictionary.put attribute value /.attrs)
                                 (list@map (|>> #/.Text) children))]]
            ($_ _.and
                (_.test "Can parse text."
                        (E.default #0
                                   (do E.monad
                                     [output (</>.run </>.text
                                                      (#/.Text text))]
                                     (wrap (text@= text output)))))
                (_.test "Can parse attributes."
                        (E.default #0
                                   (do E.monad
                                     [output (</>.run (p.before </>.ignore
                                                                (</>.attribute attribute))
                                                      node)]
                                     (wrap (text@= value output)))))
                (_.test "Can parse nodes."
                        (E.default #0
                                   (do E.monad
                                     [_ (</>.run (p.before </>.ignore
                                                           (</>.node tag))
                                                 node)]
                                     (wrap #1))))
                (_.test "Can parse children."
                        (E.default #0
                                   (do E.monad
                                     [outputs (</>.run (</>.children (p.some </>.text)) node)]
                                     (wrap (:: (list.equivalence text.equivalence) =
                                               children
                                               outputs)))))
                ))
          )))