parsing - 如何测试不符合 Instaparse 语法(Clojure)的文本?

标签 parsing exception clojure context-free-grammar instaparse

我在 Instaparse (Clojure) 中编写了一个使用上下文无关语法解析字符串的项目。现在我想测试几个输入字符串的解析结果。某些输入字符串可能不适合语法。到目前为止,我只测试了“解析的字符串不符合预期”。但我认为使用 (is (thrown? ...)) 测试异常会更准确.是否有异常抛出?在我看来,生成了一些输出(包含 Parse error...),但没有抛出异常。

我的 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)

我应该如何测试错误(这里:当句子不是以 . 结尾而是以 ! 结尾时)?

最佳答案

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?"))))

这种方法使用 instaparse 来漂亮地打印失败并将其包装在异常中。另一种方法是使用 ex-info如本 answer 中所述.

关于parsing - 如何测试不符合 Instaparse 语法(Clojure)的文本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26338945/

相关文章:

c - 解析器的左联想语法

android - 从 SOAP 响应中获取 XML 文件作为值 <BooksResult>xml</BooksResult>

php - 使用 php 使用 getElementsByTagName 检索 rss 图像

clojure - 如何在 clojure 中以编程方式创建多个编译时定义?

clojure - 如何在 clojure 中转置嵌套向量

parsing - LR 属性解析器技术

java - Java中的异常线程中的异常 "AWT-EventQueue-0"java.lang.NullPointerException

php - 在类中使用 $this 从空值创建默认对象

exception - 如何从 CFC 文件获取异常详细信息

clojure - Clojure 循环数据结构必须涉及像 ref 这样的结构吗?