-
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathtest.clj
More file actions
executable file
·145 lines (112 loc) · 5.81 KB
/
test.clj
File metadata and controls
executable file
·145 lines (112 loc) · 5.81 KB
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/usr/bin/env bb
(require '[instaparse.core :as insta]
'[clojure.string :as str])
(def as-and-bs
(insta/parser
"S = AB*
AB = A B
A = 'a'+
B = 'b'+"))
(assert (= [:S [:AB [:A "a" "a" "a" "a" "a"] [:B "b" "b" "b"]] [:AB [:A "a" "a" "a" "a"] [:B "b" "b"]]] (insta/parse as-and-bs "aaaaabbbaaaabb")))
(def failure (insta/parse as-and-bs "xaaaaabbbaaaabb"))
(assert (insta/failure? failure) "should be true")
;; test get-failure
(let [f (insta/get-failure failure)]
(assert (map? f) "get-failure should return a map")
(assert (contains? f :index) "failure should contain :index")
(assert (contains? f :line) "failure should contain :line")
(assert (contains? f :column) "failure should contain :column"))
(assert (nil? (insta/get-failure (insta/parse as-and-bs "aabb")))
"get-failure on successful parse should return nil")
(def commit-msg-grammar
"A PEG grammar to validate and parse conventional commit messages."
(str
"<S> = (HEADER <EMPTY-LINE> FOOTER GIT-REPORT? <NEWLINE>*)
/ ( HEADER <EMPTY-LINE> BODY (<EMPTY-LINE> FOOTER)? GIT-REPORT? <NEWLINE>*)
/ (HEADER <EMPTY-LINE> BODY GIT-REPORT? <NEWLINE>*)
/ (HEADER GIT-REPORT? <NEWLINE>*);"
"<HEADER> = TYPE (<'('>SCOPE<')'>)? <':'> <SPACE> SUBJECT;"
"TYPE = 'feat' | 'fix' | 'refactor' | 'perf' | 'style' | 'test' | 'docs' | 'build' | 'ops' | 'chore';"
"SCOPE = #'[a-zA-Z0-9]+';"
"SUBJECT = TEXT ISSUE-REF? TEXT? !'.';"
"BODY = (!PRE-FOOTER PARAGRAPH) / (!PRE-FOOTER PARAGRAPH (<EMPTY-LINE> PARAGRAPH)*);"
"PARAGRAPH = (ISSUE-REF / TEXT / (NEWLINE !NEWLINE))+;"
"PRE-FOOTER = NEWLINE+ FOOTER;"
"FOOTER = FOOTER-ELEMENT (<NEWLINE> FOOTER-ELEMENT)*;"
"FOOTER-ELEMENT = FOOTER-TOKEN <':'> <WHITESPACE> FOOTER-VALUE;"
"FOOTER-TOKEN = ('BREAKING CHANGE' (<'('>SCOPE<')'>)?) / #'[a-zA-Z\\-^\\#]+';"
"FOOTER-VALUE = (ISSUE-REF / TEXT)+;"
"GIT-REPORT = (<EMPTY-LINE> / <NEWLINE>) COMMENT*;"
"COMMENT = <'#'> #'[^\\n]*' <NEWLINE?> ;"
"ISSUE-REF = <'#'> ISSUE-ID;"
"ISSUE-ID = #'([A-Z]+\\-)?[0-9]+';"
"TEXT = #'[^\\n\\#]+';"
"SPACE = ' ';"
"WHITESPACE = #'\\s';"
"NEWLINE = <'\n'>;"
"EMPTY-LINE = <'\n\n'>;"))
(def commit-msg-parser-hiccup (insta/parser commit-msg-grammar))
(def commit-msg-parser-enlive (insta/parser commit-msg-grammar :output-format :enlive))
(assert (= '([:TYPE "feat"] [:SUBJECT [:TEXT "adding a new awesome feature"]])
(insta/parse commit-msg-parser-hiccup "feat: adding a new awesome feature")))
(assert (= '("feat::" "ADDING A NEW AWESOME FEATURE")
(insta/transform {:TEXT reverse
:SUBJECT (comp str/reverse str/upper-case str/join)
:TYPE (fn [t] (str t "::"))}
(insta/parse commit-msg-parser-hiccup "feat: adding a new awesome feature"))))
;; test enlive
(assert (= '({:tag :TYPE, :content ("feat")}
{:tag :SUBJECT,
:content ({:tag :TEXT, :content ("adding a new awesome feature")})})
(insta/parse commit-msg-parser-enlive "feat: adding a new awesome feature")))
(assert (= '("feat::" "ADDING A NEW AWESOME FEATURE")
(insta/transform {:TEXT reverse
:SUBJECT (comp str/reverse str/upper-case str/join)
:TYPE (fn [t] (str t "::"))}
(insta/parse commit-msg-parser-enlive "feat: adding a new awesome feature"))))
;; test slurp - note the slurp happens inside Clojure code in the pod.
(assert (= (let [p (insta/parser "test-resources/commit-msg-grammar.txt")]
(insta/parse p "feat: adding a new awesome feature"))
'([:TYPE "feat"] [:SUBJECT [:TEXT "adding a new awesome feature"]])))
;; test URI - grammar loaded via java.net.URL
(assert (= (let [p (insta/parser (-> (clojure.java.io/file "test-resources/commit-msg-grammar.txt")
.toURI .toURL))]
(insta/parse p "feat: adding a new awesome feature"))
'([:TYPE "feat"] [:SUBJECT [:TEXT "adding a new awesome feature"]])))
;; test add-line-and-column-info-to-metadata
(let [text "aaaaabbbaaaabb"
result (insta/parse as-and-bs text)
annotated (insta/add-line-and-column-info-to-metadata text result)]
(assert (= {:instaparse.gll/start-line 1
:instaparse.gll/start-column 1
:instaparse.gll/end-line 1
:instaparse.gll/end-column 15
:instaparse.gll/start-index 0
:instaparse.gll/end-index 14}
(meta annotated))
"root should have line/column metadata"))
;; test IFn - parser is directly callable as a function.
(assert (= (commit-msg-parser-hiccup "feat: adding a new awesome feature")
'([:TYPE "feat"] [:SUBJECT [:TEXT "adding a new awesome feature"]])))
;; test defparser
(defn tidy-string [s]
(-> s str/trim-newline (str/replace #"\"" "")))
(def msecs-reg #"^\d*\.?\d*$")
;; "A parser to read the output of `time`."
(insta/defparser elapsed-time-parser
(str
"<S> = <Preamable> Msecs <Postamble>;"
"Preamable = \"Elapsed time: \";"
"Postamble = \" msecs\";"
"<Msecs> = #'[^ ]*'" ))
(defn read-time [s]
(->> s
tidy-string
(insta/parse elapsed-time-parser)
first
Float.))
;; assert that most of the work is done at compile time with defparser when passed a string
#_(assert (>))
;; just evaluate the two times for now.
(read-time (with-out-str (time (insta/parser "S = A B; A = 'a'+; B = 'b'+"))))
(read-time (with-out-str (time (insta/defparser time-parser "S = A B; A = 'a'+; B = 'b'+"))))