Javascript 如何通过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

我有一个S表达式数组

  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}失败`
)
}