Javascript 如何通过S表达式树满足测试用例
我有一个S表达式数组Javascript 如何通过S表达式树满足测试用例,javascript,s-expression,Javascript,S Expression,我有一个S表达式数组 const condition = [ 'OR', [ 'AND', ['==', '$State', 'Alabama'], ['==', '$Profession', 'Software development'] ], ['==', '$Undefined', ''], [ 'AND', ['==', '$State', 'Texas'] ], [ 'OR', [ 'O
const condition = [
'OR',
[
'AND',
['==', '$State', 'Alabama'],
['==', '$Profession', 'Software development']
],
['==', '$Undefined', ''],
[
'AND',
['==', '$State', 'Texas']
],
[
'OR',
[
'OR',
['==', '$Profession', 'Tradesperson']
]
]
]
我有这个需要满足的测试用例和功能
const testCases = [
[{'State': 'Alabama', 'Profession': 'Software development'}, true],
[{'State': 'Texas'}, true],
[{'State': 'Alabama', 'Profession': 'Gaming'}, false],
[{'State': 'Utah'}, false],
[{'Profession': 'Town crier'}, false],
[{'Profession': 'Tradesperson'}, true],
[{}, false]
]
for (const [index, [context, expected]] of testCases.entries()) {
console.log(
evaluate(condition as Condition, context) === expected
? `${index} ok`
: `${index} FAIL`
)
}
到目前为止,我得到的是
function evaluate (condition: Condition, context: Context): boolean {
if (isLogicalCondition(condition)) {
const [operator, ...conditions] = condition
}
if (isComparisonCondition(condition)) {
const [operator, variable, value] = condition
}
return false
}
函数、类型和变量如下所示
type Context = {
[k: string]: string | undefined
}
enum LogicalOperator {
And = 'AND',
Or = 'OR'
}
enum ComparisonOperator {
Eq = '=='
}
type Operator = LogicalOperator | ComparisonOperator
type LogicalCondition = [LogicalOperator, ...Array<Condition>]
type Variable = string
type Value = string
type ComparisonCondition = [ComparisonOperator, Variable, Value]
type Condition = LogicalCondition | ComparisonCondition
function isLogicalCondition (condition: Condition): condition is LogicalCondition {
return Object.values(LogicalOperator).includes(condition[0] as LogicalOperator)
}
function isComparisonCondition (condition: Condition): condition is ComparisonCondition {
return Object.values(ComparisonOperator).includes(condition[0] as ComparisonOperator)
}
类型上下文={
[k:字符串]:字符串|未定义
}
枚举逻辑运算符{
和='和',
或=‘或’
}
枚举比较运算符{
Eq='='
}
类型运算符=逻辑运算符|比较运算符
类型LogicalCondition=[LogicalOperator,…数组]
类型变量=字符串
类型值=字符串
类型ComparisonCondition=[ComparisonOperator,Variable,Value]
类型条件=逻辑条件|比较条件
函数isLogicalCondition(条件:条件):条件是逻辑条件{
返回对象.values(LogicalOperator).includes(条件[0]作为LogicalOperator)
}
函数是比较条件(条件:条件):条件是比较条件{
返回Object.values(ComparisonOperator).includes(条件[0]作为ComparisonOperator)
}
我的问题是,我如何以一种足够抽象的方式来思考这个问题,从而在不硬编码测试结果的情况下满足测试要求?我完全迷路了…你应该使用递归。“OR”操作符转换为
一些方法调用,“and”转换为每个方法调用
为了实现相等,您应该处理任何“$”前缀,在这种情况下,您必须在上下文对象中查找该值。最好不要假设第一个参数总是有“$”,所以我建议对两个参数都使用映射器,每次都处理潜在的“$”
您可以使用此功能:
function evaluate(condition, context) {
let [operator, ...arguments] = condition;
if (operator === "==") {
return arguments.map(arg => arg[0] === "$" ? context[arg.slice(1)] : arg)
.reduce(Object.is);
}
if (operator === "OR") {
return arguments.some(argument => evaluate(argument, context));
}
if (operator === "AND") {
return arguments.every(argument => evaluate(argument, context));
}
throw "unknown operator " + operator;
}
运行测试用例:
函数求值(条件、上下文){
让[运算符,…参数]=条件;
如果(运算符==“=”){
返回arguments.map(arg=>arg[0]=“$”?上下文[arg.slice(1)]:arg)
.reduce(Object.is);
}
如果(运算符==“或”){
返回参数。一些(参数=>evaluate(参数,上下文));
}
如果(运算符=“和”){
返回参数.every(参数=>evaluate(参数,上下文));
}
抛出“未知运算符”+运算符;
}
常数条件=[
或",,
[
"及",,
['='、'$State'、'阿拉巴马州'],
['='、'$Profession'、'软件开发']
],
['='、'$Undefined'、''],
[
"及",,
['='、'$State'、'德克萨斯']
],
[
或",,
[
或",,
['='、'$Profession'、'商人']
]
]
]
常量测试用例=[
[{'State':'Alabama','Profession':'softwaredevelopment'},正确],
[{'State':'Texas'},对],
[{'State':'Alabama','Profession':'Gaming'},假],
[{'State':'犹他州'},false],
[{'Profession':'towncrier'},false],
[{'Profession':'Tradesperson'},对],
[{},错]
]
for(testCases.entries()的常量[index,[context,expected]]{
console.log(
评估(条件、上下文)==预期
?`${index}正常`
:`${index}失败`
)
}