How to check texts that do not correspond to Instaparse (Clojure) grammar?

I wrote a project to parse strings using context-free grammar in Instaparse (Clojure). Now I would like to test several input lines for their parsing results. Some input lines may not fit into the grammar. So far I have tested only "parsed strings that do not meet expectations." But I think it would be more accurate to check for exceptions using (is (thrown? ...)) . Are there any exceptions? It seems to me that some output is generated (containing Parse error... ), but an exception is not generated.

My .clj project:

 (defproject com.stackoverflow.clojure/tests "0.1.0-SNAPSHOT" :description "Tests of Clojure test-framework." :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.6.0"] [instaparse "1.3.4"]]) 

My main source:

 (ns com.stackoverflow.clojure.testInstaparseWrongGrammar (:require [instaparse.core :as insta])) (def parser (insta/parser " <sentence> = words <DOT> DOT = '.' <words> = word (<SPACE> word)* SPACE = ' ' word = #'(?U)\\w+' ")) (defn formatter [expr] (->> (parser expr) (insta/transform {:word identity}) (apply str))) 

My test source:

 (ns com.stackoverflow.clojure.testInstaparseWrongGrammar-test (:require [clojure.test :refer :all] [com.stackoverflow.clojure.testInstaparseWrongGrammar :refer :all])) (deftest parser-tests (is (= [[:word "Hello"] [:word "World"]] (parser "Hello World."))) (is (not (= [[:word "Hello"] [:word "World"]] (parser "Hello World?")))) ;(parser "Hello World?") gives: ; ;Parse error at line 1, column 12: ;Hello World? ; ^ ;Expected one of: ;"." (followed by end-of-string) ;" " ) (deftest formatter-tests (is (= "HelloWorld" (formatter "Hello World."))) (is (not (= "HelloWorld" (formatter "Hello World?")))) ;(formatter "Hello World?") gives: ;"[:index 11][:reason [{:tag :string, :expecting \".\", :full true} {:tag :string, :expecting \" \"}]][:text \"Hello World?\"][:column 12][:line 1]" ) ; run the tests (run-tests) 

How should I check for errors (here: when the sentence does not end with . , But with ! )?

+6
source share
1 answer

Instaparse does not throw an exception on an analysis error; instead, it returns a โ€œfailure objectโ€ (ref: parsing errors ). You can check for an object with an error (insta/failure? result) .

If you want your parser / formatting to throw an exception on unexpected input, add this to your kernel:

 (ns com.stackoverflow.clojure.testInstaparseWrongGrammar (:require [instaparse.core :as insta]) (:require [instaparse.failure :as fail])) (def raw-parser (insta/parser " <sentence> = words <DOT> DOT = '.' <words> = word (<SPACE> word)* SPACE = ' ' word = #'(?U)\\w+' ")) ; pretty-print a failure as a string (defn- failure->string [result] (with-out-str (fail/pprint-failure result))) ; create an Exception with the pretty-printed failure message (defn- failure->exn [result] (Exception. (failure->string result))) (defn parser [expr] (let [result (raw-parser expr)] (if (insta/failure? result) (throw (failure->exn result)) result))) (defn formatter [expr] (->> (parser expr) (insta/transform {:word identity}) (apply str))) 

... and now you can use (is (thrown? ...)) in the test:

 (deftest parser-tests (is (= [[:word "Hello"] [:word "World"]] (parser "Hello World."))) (is (thrown? Exception (= [[:word "Hello"] [:word "World"]] (parser "Hello World?")))) 

This approach uses instaparse to pretty much print errors and wraps in Exception. Another approach is to use ex-info as described in this.

+6
source

Source: https://habr.com/ru/post/976669/


All Articles