2014-10-13 9 views
6

मैंने Instaparse (क्लोजर) में संदर्भ मुक्त व्याकरण का उपयोग कर तारों को पार्स करने के लिए एक प्रोजेक्ट लिखा था। अब मैं अपने विश्लेषण परिणामों के लिए कई इनपुट-स्ट्रिंग का परीक्षण करना चाहता हूं। कुछ इनपुट स्ट्रिंग व्याकरण में फिट नहीं हो सकते हैं। अब तक मैंने केवल "पार्स किए गए तारों के लिए परीक्षण की उम्मीद नहीं की है"। लेकिन मुझे लगता है कि (is (thrown? ...)) का उपयोग करके अपवादों के परीक्षण के लिए यह अधिक सटीक होगा। क्या अपवाद फेंक दिए गए हैं? ऐसा लगता है कि कुछ आउटपुट (Parse error... युक्त) उत्पन्न होता है, लेकिन कोई अपवाद नहीं फेंक दिया जाता है।एक Instaparse-व्याकरण (क्लोजर) फिट करने वाले ग्रंथों का परीक्षण कैसे करें?

मेरे project.clj है:

(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"]]) 

मेरे कोर स्रोत है:

(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))) 

मेरा परीक्षण स्रोत है:

(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) 

मैं कैसे त्रुटियों के लिए परीक्षण करना चाहिए (यहाँ : जब वाक्य . के साथ समाप्त नहीं होता है लेकिन ! के साथ)?

उत्तर

6

Instaparse पार्स त्रुटि पर अपवाद नहीं फेंकता है; इसके बजाय, यह एक "विफलता वस्तु" देता है (रेफरी: parse errors)। आप (insta/failure? result) के साथ विफलता ऑब्जेक्ट का परीक्षण कर सकते हैं।

आप अपने पार्सर/फ़ॉर्मेटर, अप्रत्याशित इनपुट पर एक अपवाद फेंक अपने मूल करने के लिए कि जोड़ना चाहते हैं:

(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))) 

... और अब आप परीक्षा में (is (thrown? ...)) उपयोग कर सकते हैं:

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

यह दृष्टिकोण विफलता को सुंदर प्रिंट करने के लिए इंस्टैपर्स का उपयोग करता है और अपवाद में लपेटता है। एक और तरीका ex-info का उपयोग करना है जैसा कि इस answer में उल्लिखित है।

+0

विफलता-वस्तु से मुझे जानकारी कैसे प्राप्त हो सकती है? शुरुआत के लिए मैं दो चीजें करना चाहूंगा (यदि संभव हो)। ** पहले **: मेरी अपवाद विधि में लाइन-नंबर जोड़ें। ** दूसरा **: मेरे अपवाद पर अच्छी तरह से स्वरूपित त्रुटि-संदेश जोड़ें। ** इसके अलावा **, एक नया अपवाद वर्ग बनाने के लिए, यह जावा में इसे लागू करने का सबसे आसान तरीका प्रतीत होता है - क्या यह सही है? – Edward

+0

... और 'विफलता ऑब्जेक्ट' से आपका क्या मतलब है। मैंने सोचा कि क्लोजर में कोई ऑब्जेक्ट्स (विधियों और चर के साथ) नहीं है। तो मैं (सामान्य रूप से) उन ऑब्जेक्ट्स के तरीकों और चर का उपयोग कैसे कर सकता हूं? – Edward

+0

@ ऊपर दिए गए कोड को अपवाद में पार्स त्रुटि (रेखा, कॉलम, आदि) का एक टेक्स्ट विवरण शामिल है। "विफलता ऑब्जेक्ट" एक नक्शा है (तकनीकी रूप से 'defrecord' द्वारा निर्मित 'रिकॉर्ड') जिसमें कुछ प्रसिद्ध कुंजी हैं; उदाहरण के लिए, लाइन नंबर को '(: लाइन परिणाम)' के साथ एक्सेस किया जा सकता है। – lnmx

संबंधित मुद्दे