2014-10-13 11 views
6

Tôi đã viết một dự án phân tích chuỗi bằng ngữ pháp không có ngữ cảnh trong Instaparse (Clojure). Bây giờ tôi muốn kiểm tra một số đầu vào-Strings cho kết quả phân tích cú pháp của họ. Một số chuỗi đầu vào có thể không phù hợp với ngữ pháp. Cho đến nay tôi chỉ thử nghiệm cho "chuỗi phân tích cú pháp không phù hợp với kỳ vọng". Nhưng tôi nghĩ rằng nó sẽ chính xác hơn để kiểm tra các trường hợp ngoại lệ bằng cách sử dụng (is (thrown? ...)). Có trường hợp ngoại lệ ném? Dường như với tôi rằng một số đầu ra (chứa Parse error...) được tạo ra, nhưng không có ngoại lệ nào được ném.Làm cách nào để kiểm tra các văn bản không phù hợp với ngữ pháp Instaparse (Clojure)?

project.clj của tôi là:

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

nguồn cốt lõi của tôi là:

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

nguồn thử nghiệm của tôi là:

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

Làm thế nào tôi nên kiểm tra các lỗi (đây : khi câu không kết thúc bằng . nhưng với một số !)?

Trả lời

6

Instaparse không ném ngoại lệ lên lỗi phân tích cú pháp; thay vào đó, nó trả về một "đối tượng thất bại" (ref: parse errors). Bạn có thể kiểm tra đối tượng thất bại với (insta/failure? result).

Nếu bạn muốn phân tích cú pháp của bạn/formatter để ném một ngoại lệ về đầu vào bất ngờ, thêm rằng đến cốt lõi của bạn:

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

... và bây giờ bạn có thể sử dụng trong các thử nghiệm (is (thrown? ...)):

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

Cách tiếp cận này sử dụng instaparse để in đẹp sự thất bại và kết thúc tốt đẹp trong một ngoại lệ. Một cách tiếp cận khác là sử dụng ex-info như được nêu trong answer này.

+0

Làm cách nào để lấy thông tin từ đối tượng không thành công? Ban đầu tôi muốn làm hai việc (nếu có thể). ** Đầu tiên **: Thêm số dòng vào phương thức ngoại lệ của tôi. ** Thứ hai **: Thêm thông báo lỗi được định dạng độc đáo vào ngoại lệ của tôi. ** Hơn nữa **, để tạo một lớp Ngoại lệ mới, nó có vẻ là cách dễ nhất để thực hiện nó trong Java - đúng không? – Edward

+0

... và bạn có ý nghĩa gì bởi 'đối tượng thất bại'. Tôi nghĩ rằng không có một đối tượng (với các phương pháp và các biến) trong Clojure. Vậy làm thế nào tôi có thể (nói chung) phương pháp truy cập và các biến của các đối tượng? – Edward

+0

@Edward mã ở trên bây giờ bao gồm mô tả văn bản của lỗi phân tích cú pháp (dòng, cột, v.v.) trong Ngoại lệ. "Đối tượng thất bại" là một bản đồ (về mặt kỹ thuật là một "bản ghi" được tạo bởi 'defrecord') có một số phím nổi tiếng; ví dụ, số dòng có thể được truy cập bằng '(: kết quả dòng)'. – lnmx

Các vấn đề liên quan