为ANSI转义码字符串解析器编写QuickCheck属性:断言内容如何确定?
为Haskell的ANSI字符串解析函数编写QuickCheck属性
现有代码定义
我们有如下Haskell代码,定义了表示ANSI编码字符串解析结果的Slice和Color类型,以及处理带ANSI转义码字符串的categorize函数:
-- 表示ANSI编码字符串的解析结果 data Slice = Slice { text :: String, color :: Color } newtype Color = Color { string :: String } -- 接收带ANSI转义码的字符串,返回切片列表 categorize:: String -> [Slice] categorize codedString = ...
QuickCheck测试框架问题
我已经实现了生成ANSI转义码字符串的QuickCheck生成器ansiEscapeStrings,但不确定测试断言部分(代码中的WHAT_GOES_HERE)应该填写什么内容:
-- 生成ANSI编码字符串的QuickCheck生成器 ansiEscapeStrings :: Gen String ansiEscapeStrings = ... main = verboseCheck $ forAll ansiEscapeStrings (\codedString -> categorize codedString == WHAT_GOES_HERE)
注:我已经完成了长度、空列表等基础属性的测试。
断言部分的可行方案
由于直接对比categorize的结果需要一个可信的参考解析实现,你可以从以下几个核心不变量入手编写断言:
1. 文本内容一致性
所有切片的文本拼接后,应该等于原字符串去掉所有ANSI转义码的结果。首先实现一个去除ANSI转义码的辅助函数:
-- 去除字符串中的ANSI转义码(ESC[...]m格式) stripAnsi :: String -> String stripAnsi [] = [] stripAnsi ('\ESC':cs) = stripAnsi $ drop 1 $ dropWhile (/= 'm') cs stripAnsi (c:cs) = c : stripAnsi cs
对应的断言:
concatMap text (categorize codedString) == stripAnsi codedString
2. 切片的颜色正确性
如果能实现一个简单的参考解析器(逻辑比categorize更直白,用于验证),可以直接对比两者的切片结果。比如参考解析器的大致实现:
-- 参考解析器:跟踪当前颜色,生成预期的切片列表 expectedSlices :: String -> [Slice] expectedSlices s = go s (Color "") [] where go [] _ acc = reverse acc go ('\ESC':cs) currentColor acc = let (escSeq, rest) = span (/= 'm') cs newColor = Color ('\ESC' : escSeq ++ "m") in go rest newColor acc go cs currentColor acc = let (plainText, rest) = span (/= '\ESC') cs newSlice = Slice plainText currentColor in go rest currentColor (newSlice:acc)
对应的断言:
categorize codedString == expectedSlices codedString
3. 无空文本切片
除了原字符串本身不含有效文本(只有转义码)的情况,所有切片的文本都不应为空:
all (not . null . text) (categorize codedString) || stripAnsi codedString == ""
你可以根据需求选择单个或组合这些断言,替换原代码中的WHAT_GOES_HERE部分。
内容的提问来源于stack exchange,提问作者Refael Sheinker
相关产品推荐
相关产品推荐

