cedar_policy_core/
evaluator.rs

1/*
2 * Copyright 2022-2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//! This module contains the Cedar evaluator.
18
19use crate::ast::*;
20use crate::entities::{Dereference, Entities};
21use crate::extensions::Extensions;
22use std::collections::HashMap;
23use std::sync::Arc;
24
25mod err;
26pub use err::EvaluationError;
27pub(crate) use err::*;
28use itertools::Either;
29use smol_str::SmolStr;
30
31const REQUIRED_STACK_SPACE: usize = 1024 * 100;
32
33/// Evaluator object.
34///
35/// Conceptually keeps the evaluation environment as part of its internal state,
36/// because we will be repeatedly invoking the evaluator on every policy in a
37/// Slice.
38pub struct Evaluator<'e> {
39    /// `Principal` for the current request
40    principal: EntityUIDEntry,
41    /// `Action` for the current request
42    action: EntityUIDEntry,
43    /// `Resource` for the current request
44    resource: EntityUIDEntry,
45    /// `Context` for the current request; this will be a Record type
46    context: PartialValue,
47    /// Entities which we use to resolve entity references.
48    ///
49    /// This is a reference, because the `Evaluator` doesn't need ownership of
50    /// (or need to modify) the `Entities`. One advantage of this is that you
51    /// could create multiple `Evaluator`s without copying the `Entities`.
52    entities: &'e Entities,
53    /// Extensions which are active for this evaluation
54    extensions: &'e Extensions<'e>,
55    /// Entity attribute value cache
56    ///
57    /// We evaluate entity attribute expressions upon the creation of an evaluator.
58    entity_attr_values: EntityAttrValues<'e>,
59}
60
61/// Evaluator for "restricted" expressions. See notes on `RestrictedExpr`.
62#[derive(Debug)]
63pub struct RestrictedEvaluator<'e> {
64    /// Extensions which are active for this evaluation
65    extensions: &'e Extensions<'e>,
66}
67
68impl<'e> RestrictedEvaluator<'e> {
69    /// Create a fresh evaluator for evaluating "restricted" expressions
70    pub fn new(extensions: &'e Extensions<'e>) -> Self {
71        Self { extensions }
72    }
73
74    /// Interpret a `RestrictedExpr` into a `Value` in this evaluation environment.
75    ///
76    /// May return an error, for instance if an extension function returns an error
77    pub fn interpret(&self, e: BorrowedRestrictedExpr<'_>) -> Result<Value> {
78        match self.partial_interpret(e)? {
79            PartialValue::Value(v) => Ok(v),
80            PartialValue::Residual(r) => Err(EvaluationError::NonValue(r)),
81        }
82    }
83
84    /// Interpret a `RestrictedExpr` into a `Value` in this evaluation environment.
85    ///
86    /// May return an error, for instance if an extension function returns an error
87    pub fn partial_interpret(&self, e: BorrowedRestrictedExpr<'_>) -> Result<PartialValue> {
88        stack_size_check()?;
89
90        match e.as_ref().expr_kind() {
91            ExprKind::Lit(lit) => Ok(lit.clone().into()),
92            ExprKind::Set(items) => {
93                let vals = items
94                    .iter()
95                    .map(|item| self.partial_interpret(BorrowedRestrictedExpr::new_unchecked(item))) // assuming the invariant holds for `e`, it will hold here
96                    .collect::<Result<Vec<_>>>()?;
97                match split(vals) {
98                    Either::Left(values) => Ok(Value::Set(values.collect()).into()),
99                    Either::Right(residuals) => Ok(Expr::set(residuals).into()),
100                }
101            }
102            ExprKind::Unknown{name, type_annotation} => Ok(PartialValue::Residual(Expr::unknown_with_type(name.clone(), type_annotation.clone()))),
103            ExprKind::Record { pairs } => {
104                let map = pairs
105                    .iter()
106                    .map(|(k, v)| Ok((k.clone(), self.partial_interpret(BorrowedRestrictedExpr::new_unchecked(v))?))) // assuming the invariant holds for `e`, it will hold here
107                    .collect::<Result<Vec<_>>>()?;
108                let (names, attrs) : (Vec<_>, Vec<_>) = map.into_iter().unzip();
109                match split(attrs) {
110                    Either::Left(values) => Ok(Value::Record(Arc::new(names.into_iter().zip(values).collect())).into()),
111                    Either::Right(residuals) => Ok(Expr::record(names.into_iter().zip(residuals)).into()),
112                }
113            }
114            ExprKind::ExtensionFunctionApp { op, args } => {
115                let args = args
116                    .iter()
117                    .map(|arg| self.partial_interpret(BorrowedRestrictedExpr::new_unchecked(arg))) // assuming the invariant holds for `e`, it will hold here
118                    .collect::<Result<Vec<_>>>()?;
119                match split(args) {
120                    Either::Left(values) => {
121                        let values : Vec<_> = values.collect();
122                        let efunc = self.extensions.func(&op.function_name)?;
123                        efunc.call(&values)
124                    },
125                    Either::Right(residuals) => Ok(Expr::call_extension_fn(op.function_name.clone(), residuals.collect()).into()),
126                }
127            },
128            expr => panic!("internal invariant violation: BorrowedRestrictedExpr somehow contained this expr case: {expr:?}"),
129        }
130    }
131}
132
133struct EntityAttrValues<'a> {
134    attrs: HashMap<EntityUID, HashMap<SmolStr, PartialValue>>,
135    entities: &'a Entities,
136}
137
138impl<'a> EntityAttrValues<'a> {
139    pub fn new<'e>(entities: &'a Entities, extensions: &'e Extensions<'e>) -> Result<Self> {
140        let restricted_eval = RestrictedEvaluator::new(extensions);
141        // Eagerly evaluate each attribute expression in the entities.
142        let attrs = entities
143            .iter()
144            .map(|entity| {
145                Ok((
146                    entity.uid(),
147                    entity
148                        .attrs()
149                        .iter()
150                        .map(|(attr, v)| {
151                            Ok((
152                                attr.to_owned(),
153                                restricted_eval.partial_interpret(v.as_borrowed())?,
154                            ))
155                        })
156                        .collect::<Result<HashMap<SmolStr, PartialValue>>>()?,
157                ))
158            })
159            .collect::<Result<HashMap<EntityUID, HashMap<SmolStr, PartialValue>>>>()?;
160        Ok(Self { attrs, entities })
161    }
162
163    pub fn get(&self, uid: &EntityUID) -> Dereference<'_, HashMap<SmolStr, PartialValue>> {
164        match self.entities.entity(uid) {
165            Dereference::NoSuchEntity => Dereference::NoSuchEntity,
166            Dereference::Residual(r) => Dereference::Residual(r),
167            Dereference::Data(_) => self
168                .attrs
169                .get(uid)
170                .map(Dereference::Data)
171                .unwrap_or_else(|| Dereference::NoSuchEntity),
172        }
173    }
174}
175
176impl<'q, 'e> Evaluator<'e> {
177    /// Create a fresh `Evaluator` for the given `request`, which uses the given
178    /// `Entities` to resolve entity references. Use the given `Extension`s when
179    /// evaluating the request.
180    ///
181    /// (An `Entities` is the entity-hierarchy portion of a `Slice`, without the
182    /// policies.)
183    ///
184    /// Can throw an error, eg if evaluating attributes in the `context` throws
185    /// an error.
186    pub fn new(
187        q: &'q Request,
188        entities: &'e Entities,
189        extensions: &'e Extensions<'e>,
190    ) -> Result<Self> {
191        // Eagerly evaluate each attribute expression in the entities.
192        let entity_attr_values = EntityAttrValues::new(entities, extensions)?;
193        Ok(Self {
194            principal: q.principal().clone(),
195            action: q.action().clone(),
196            resource: q.resource().clone(),
197            context: {
198                // evaluate each of the context attributes in an evaluator
199                // for "restricted" expressions.
200                // This prohibits them from referring to the `request`,
201                // ie, the variables `principal`, `resource`, etc.
202                // For more, see notes on `RestrictedExpr`.
203                let restricted_eval = RestrictedEvaluator::new(extensions);
204                match &q.context {
205                    None => PartialValue::Residual(Expr::unknown("context")),
206                    Some(ctxt) => restricted_eval.partial_interpret(ctxt.as_ref().as_borrowed())?,
207                }
208            },
209            entities,
210            extensions,
211            entity_attr_values,
212        })
213    }
214
215    /// Evaluate the given `Policy`, returning either a bool or an error.
216    /// The bool indicates whether the policy applies, ie, "is satisfied" for the
217    /// current `request`.
218    /// This is _different than_ "if the current `request` should be allowed" --
219    /// it doesn't consider whether we're processing a `Permit` policy or a
220    /// `Forbid` policy.
221    pub fn evaluate(&self, p: &Policy) -> Result<bool> {
222        self.interpret(&p.condition(), p.env())?.get_as_bool()
223    }
224
225    /// Partially evaluate the given `Policy`, returning one of:
226    /// 1) A boolean, if complete evaluation was possible
227    /// 2) An error, if the policy is guaranteed to error
228    /// 3) A residual, if complete evaluation was impossible
229    /// The bool indicates whether the policy applies, ie, "is satisfied" for the
230    /// current `request`.
231    /// This is _different than_ "if the current `request` should be allowed" --
232    /// it doesn't consider whether we're processing a `Permit` policy or a
233    /// `Forbid` policy.
234    pub fn partial_evaluate(&self, p: &Policy) -> Result<Either<bool, Expr>> {
235        match self.partial_interpret(&p.condition(), p.env())? {
236            PartialValue::Value(v) => v.get_as_bool().map(Either::Left),
237            PartialValue::Residual(e) => Ok(Either::Right(e)),
238        }
239    }
240
241    /// Run an expression as far as possible.
242    /// however, if an error is encountered, instead of error-ing, wrap the error
243    /// in a call the `error` extension function.
244    pub fn run_to_error(
245        &self,
246        e: &Expr,
247        slots: &SlotEnv,
248    ) -> (PartialValue, Option<EvaluationError>) {
249        match self.partial_interpret(e, slots) {
250            Ok(e) => (e, None),
251            Err(err) => {
252                let arg = Expr::val(format!("{err}"));
253                (
254                    PartialValue::Residual(Expr::call_extension_fn(
255                        "error".parse().unwrap(),
256                        vec![arg],
257                    )),
258                    Some(err),
259                )
260            }
261        }
262    }
263
264    /// Interpret an `Expr` into a `Value` in this evaluation environment.
265    ///
266    /// Ensures the result is not a residual.
267    /// May return an error, for instance if the `Expr` tries to access an
268    /// attribute that doesn't exist.
269    pub fn interpret(&self, e: &Expr, slots: &SlotEnv) -> Result<Value> {
270        match self.partial_interpret(e, slots)? {
271            PartialValue::Value(v) => Ok(v),
272            PartialValue::Residual(r) => Err(EvaluationError::NonValue(r)),
273        }
274    }
275
276    /// Interpret an `Expr` into a `Value` in this evaluation environment.
277    ///
278    /// May return a residual expression, if the input expression is symbolic.
279    /// May return an error, for instance if the `Expr` tries to access an
280    /// attribute that doesn't exist.
281    pub fn partial_interpret(&self, e: &Expr, slots: &SlotEnv) -> Result<PartialValue> {
282        stack_size_check()?;
283
284        match e.expr_kind() {
285            ExprKind::Lit(lit) => Ok(lit.clone().into()),
286            ExprKind::Slot(id) => slots
287                .get(id)
288                .ok_or_else(|| err::EvaluationError::TemplateInstantiationError(*id))
289                .map(|euid| PartialValue::from(euid.clone())),
290            ExprKind::Var(v) => match v {
291                Var::Principal => Ok(self.principal.evaluate(*v)),
292                Var::Action => Ok(self.action.evaluate(*v)),
293                Var::Resource => Ok(self.resource.evaluate(*v)),
294                Var::Context => Ok(self.context.clone()),
295            },
296            ExprKind::Unknown { .. } => Ok(PartialValue::Residual(e.clone())),
297            ExprKind::If {
298                test_expr,
299                then_expr,
300                else_expr,
301            } => self.eval_if(test_expr, then_expr, else_expr, slots),
302            ExprKind::And { left, right } => {
303                match self.partial_interpret(left, slots)? {
304                    // PE Case
305                    PartialValue::Residual(e) => Ok(PartialValue::Residual(Expr::and(
306                        e,
307                        self.run_to_error(right.as_ref(), slots).0.into(),
308                    ))),
309                    // Full eval case
310                    PartialValue::Value(v) => {
311                        if v.get_as_bool()? {
312                            match self.partial_interpret(right, slots)? {
313                                // you might think that `true && <residual>` can be optimized to `<residual>`, but this isn't true because
314                                // <residual> must be boolean, or else it needs to type error. So return `true && <residual>` to ensure
315                                // type check happens
316                                PartialValue::Residual(right) => {
317                                    Ok(PartialValue::Residual(Expr::and(Expr::val(true), right)))
318                                }
319                                // If it's an actual value, compute and
320                                PartialValue::Value(v) => Ok(v.get_as_bool()?.into()),
321                            }
322                        } else {
323                            // We can short circuit here
324                            Ok(false.into())
325                        }
326                    }
327                }
328            }
329            ExprKind::Or { left, right } => {
330                match self.partial_interpret(left, slots)? {
331                    // PE cases
332                    PartialValue::Residual(r) => Ok(PartialValue::Residual(Expr::or(
333                        r,
334                        self.run_to_error(right, slots).0.into(),
335                    ))),
336                    // Full eval case
337                    PartialValue::Value(lhs) => {
338                        if lhs.get_as_bool()? {
339                            // We can short circuit here
340                            Ok(true.into())
341                        } else {
342                            match self.partial_interpret(right, slots)? {
343                                PartialValue::Residual(rhs) =>
344                                // you might think that `false || <residual>` can be optimized to `<residual>`, but this isn't true because
345                                // <residual> must be boolean, or else it needs to type error. So return `false || <residual>` to ensure
346                                // type check happens
347                                {
348                                    Ok(PartialValue::Residual(Expr::or(Expr::val(false), rhs)))
349                                }
350                                PartialValue::Value(v) => Ok(v.get_as_bool()?.into()),
351                            }
352                        }
353                    }
354                }
355            }
356            ExprKind::UnaryApp { op, arg } => match self.partial_interpret(arg, slots)? {
357                PartialValue::Value(arg) => match op {
358                    UnaryOp::Not => match arg.get_as_bool()? {
359                        true => Ok(false.into()),
360                        false => Ok(true.into()),
361                    },
362                    UnaryOp::Neg => {
363                        let i = arg.get_as_long()?;
364                        match i.checked_neg() {
365                            Some(v) => Ok(v.into()),
366                            None => Err(EvaluationError::IntegerOverflow(
367                                IntegerOverflowError::UnaryOp { op: *op, arg },
368                            )),
369                        }
370                    }
371                },
372                // NOTE, there was a bug here found during manual review. (I forgot to wrap in unary_app call)
373                // Could be a nice target for fault injection
374                PartialValue::Residual(r) => Ok(PartialValue::Residual(Expr::unary_app(*op, r))),
375            },
376            ExprKind::BinaryApp { op, arg1, arg2 } => {
377                // NOTE: There are more precise partial eval opportunities here, esp w/ typed unknowns
378                // Current limitations:
379                //   Operators are not partially evaluated.
380                let (arg1, arg2) = match (
381                    self.partial_interpret(arg1, slots)?,
382                    self.partial_interpret(arg2, slots)?,
383                ) {
384                    (PartialValue::Value(v1), PartialValue::Value(v2)) => (v1, v2),
385                    (PartialValue::Value(v1), PartialValue::Residual(e2)) => {
386                        return Ok(PartialValue::Residual(Expr::binary_app(*op, v1.into(), e2)))
387                    }
388                    (PartialValue::Residual(e1), PartialValue::Value(v2)) => {
389                        return Ok(PartialValue::Residual(Expr::binary_app(*op, e1, v2.into())))
390                    }
391                    (PartialValue::Residual(e1), PartialValue::Residual(e2)) => {
392                        return Ok(PartialValue::Residual(Expr::binary_app(*op, e1, e2)))
393                    }
394                };
395                match op {
396                    BinaryOp::Eq => Ok((arg1 == arg2).into()),
397                    // comparison and arithmetic operators, which only work on Longs
398                    BinaryOp::Less | BinaryOp::LessEq | BinaryOp::Add | BinaryOp::Sub => {
399                        let i1 = arg1.get_as_long()?;
400                        let i2 = arg2.get_as_long()?;
401                        match op {
402                            BinaryOp::Less => Ok((i1 < i2).into()),
403                            BinaryOp::LessEq => Ok((i1 <= i2).into()),
404                            BinaryOp::Add => match i1.checked_add(i2) {
405                                Some(sum) => Ok(sum.into()),
406                                None => Err(EvaluationError::IntegerOverflow(
407                                    IntegerOverflowError::BinaryOp {
408                                        op: *op,
409                                        arg1,
410                                        arg2,
411                                    },
412                                )),
413                            },
414                            BinaryOp::Sub => match i1.checked_sub(i2) {
415                                Some(diff) => Ok(diff.into()),
416                                None => Err(EvaluationError::IntegerOverflow(
417                                    IntegerOverflowError::BinaryOp {
418                                        op: *op,
419                                        arg1,
420                                        arg2,
421                                    },
422                                )),
423                            },
424                            _ => panic!("Should have already checked that op was one of these"),
425                        }
426                    }
427                    // hierarchy membership operator; see note on `BinaryOp::In`
428                    BinaryOp::In => {
429                        let uid1 = arg1.get_as_entity()?;
430                        match self.entities.entity(uid1) {
431                            Dereference::Residual(r) => Ok(PartialValue::Residual(
432                                Expr::binary_app(BinaryOp::In, r, arg2.into()),
433                            )),
434                            Dereference::NoSuchEntity => self.eval_in(uid1, None, arg2),
435                            Dereference::Data(e) => self.eval_in(uid1, Some(e), arg2),
436                        }
437                    }
438                    // contains, which works on Sets
439                    BinaryOp::Contains => match arg1 {
440                        Value::Set(Set { fast: Some(h), .. }) => match arg2.try_as_lit() {
441                            Some(lit) => Ok((h.contains(lit)).into()),
442                            None => Ok(false.into()), // we know it doesn't contain a non-literal
443                        },
444                        Value::Set(Set { authoritative, .. }) => {
445                            Ok((authoritative.contains(&arg2)).into())
446                        }
447                        _ => Err(EvaluationError::TypeError {
448                            expected: vec![Type::Set],
449                            actual: arg1.type_of(),
450                        }),
451                    },
452                    // ContainsAll and ContainsAny, which work on Sets
453                    BinaryOp::ContainsAll | BinaryOp::ContainsAny => {
454                        let arg1_set = arg1.get_as_set()?;
455                        let arg2_set = arg2.get_as_set()?;
456                        match (&arg1_set.fast, &arg2_set.fast) {
457                            (Some(arg1_set), Some(arg2_set)) => {
458                                // both sets are in fast form, ie, they only contain literals.
459                                // Fast hashset-based implementation.
460                                match op {
461                                    BinaryOp::ContainsAll => {
462                                        Ok((arg2_set.is_subset(arg1_set)).into())
463                                    }
464                                    BinaryOp::ContainsAny => {
465                                        Ok((!arg1_set.is_disjoint(arg2_set)).into())
466                                    }
467                                    _ => panic!(
468                                        "Should have already checked that op was one of these"
469                                    ),
470                                }
471                            }
472                            (_, _) => {
473                                // one or both sets are in slow form, ie, contain a non-literal.
474                                // Fallback to slow implementation.
475                                match op {
476                                    BinaryOp::ContainsAll => {
477                                        let is_subset = arg2_set
478                                            .authoritative
479                                            .iter()
480                                            .all(|item| arg1_set.authoritative.contains(item));
481                                        Ok(is_subset.into())
482                                    }
483                                    BinaryOp::ContainsAny => {
484                                        let not_disjoint = arg1_set
485                                            .authoritative
486                                            .iter()
487                                            .any(|item| arg2_set.authoritative.contains(item));
488                                        Ok(not_disjoint.into())
489                                    }
490                                    _ => panic!(
491                                        "Should have already checked that op was one of these"
492                                    ),
493                                }
494                            }
495                        }
496                    }
497                }
498            }
499            ExprKind::MulByConst { arg, constant } => match self.partial_interpret(arg, slots)? {
500                PartialValue::Value(arg) => {
501                    let i1 = arg.get_as_long()?;
502                    match i1.checked_mul(*constant) {
503                        Some(prod) => Ok(prod.into()),
504                        None => Err(EvaluationError::IntegerOverflow(
505                            IntegerOverflowError::Multiplication {
506                                arg,
507                                constant: *constant,
508                            },
509                        )),
510                    }
511                }
512                PartialValue::Residual(r) => Ok(PartialValue::Residual(Expr::mul(r, *constant))),
513            },
514            ExprKind::ExtensionFunctionApp { op, args } => {
515                let args = args
516                    .iter()
517                    .map(|arg| self.partial_interpret(arg, slots))
518                    .collect::<Result<Vec<_>>>()?;
519                match split(args) {
520                    Either::Left(vals) => {
521                        let vals: Vec<_> = vals.collect();
522                        let efunc = self.extensions.func(&op.function_name)?;
523                        efunc.call(&vals)
524                    }
525                    Either::Right(residuals) => Ok(PartialValue::Residual(
526                        Expr::call_extension_fn(op.function_name.clone(), residuals.collect()),
527                    )),
528                }
529            }
530            ExprKind::GetAttr { expr, attr } => self.get_attr(expr.as_ref(), attr, slots),
531            ExprKind::HasAttr { expr, attr } => match self.partial_interpret(expr, slots)? {
532                PartialValue::Value(Value::Record(record)) => Ok(record.get(attr).is_some().into()),
533                PartialValue::Value(Value::Lit(Literal::EntityUID(uid))) => {
534                    match self.entities.entity(&uid) {
535                        Dereference::NoSuchEntity => Ok(false.into()),
536                        Dereference::Residual(r) => {
537                            Ok(PartialValue::Residual(Expr::has_attr(r, attr.clone())))
538                        }
539                        Dereference::Data(e) => Ok(e.get(attr).is_some().into()),
540                    }
541                }
542                PartialValue::Value(val) => Err(err::EvaluationError::TypeError {
543                    expected: vec![
544                        Type::Record,
545                        Type::entity_type(
546                            Name::parse_unqualified_name("any_entity_type")
547                                .expect("should be a valid identifier"),
548                        ),
549                    ],
550                    actual: val.type_of(),
551                }),
552                PartialValue::Residual(r) => Ok(Expr::has_attr(r, attr.clone()).into()),
553            },
554            ExprKind::Like { expr, pattern } => {
555                let v = self.partial_interpret(expr, slots)?;
556                match v {
557                    PartialValue::Value(v) => {
558                        Ok((pattern.wildcard_match(v.get_as_string()?)).into())
559                    }
560                    PartialValue::Residual(r) => Ok(Expr::like(r, pattern.iter().cloned()).into()),
561                }
562            }
563            ExprKind::Set(items) => {
564                let vals = items
565                    .iter()
566                    .map(|item| self.partial_interpret(item, slots))
567                    .collect::<Result<Vec<_>>>()?;
568                match split(vals) {
569                    Either::Left(vals) => Ok(Value::set(vals).into()),
570                    Either::Right(r) => Ok(Expr::set(r).into()),
571                }
572            }
573            ExprKind::Record { pairs } => {
574                let map = pairs
575                    .iter()
576                    .map(|(k, v)| Ok((k.clone(), self.partial_interpret(v, slots)?)))
577                    .collect::<Result<Vec<_>>>()?;
578                let (names, evalled): (Vec<SmolStr>, Vec<PartialValue>) = map.into_iter().unzip();
579                match split(evalled) {
580                    Either::Left(vals) => {
581                        Ok(Value::Record(Arc::new(names.into_iter().zip(vals).collect())).into())
582                    }
583                    Either::Right(rs) => Ok(Expr::record(names.into_iter().zip(rs)).into()),
584                }
585            }
586        }
587    }
588
589    fn eval_in(
590        &self,
591        uid1: &EntityUID,
592        entity1: Option<&Entity>,
593        arg2: Value,
594    ) -> Result<PartialValue> {
595        // `rhs` is a list of all the UIDs for which we need to
596        // check if `uid1` is a descendant of
597        let rhs = match arg2 {
598            Value::Lit(Literal::EntityUID(uid)) => vec![(*uid).clone()],
599            // we assume that iterating the `authoritative` BTreeSet is
600            // approximately the same cost as iterating the `fast` HashSet
601            Value::Set(Set { authoritative, .. }) => authoritative
602                .iter()
603                .map(|val| Ok(val.get_as_entity()?.clone()))
604                .collect::<Result<Vec<EntityUID>>>()?,
605            _ => {
606                return Err(EvaluationError::TypeError {
607                    expected: vec![
608                        Type::Set,
609                        Type::entity_type(
610                            Name::parse_unqualified_name("any_entity_type")
611                                .expect("should be a valid identifier"),
612                        ),
613                    ],
614                    actual: arg2.type_of(),
615                })
616            }
617        };
618        for uid2 in rhs {
619            if uid1 == &uid2
620                || entity1
621                    .map(|e1| e1.is_descendant_of(&uid2))
622                    .unwrap_or(false)
623            {
624                return Ok(true.into());
625            }
626        }
627        // if we get here, `uid1` is not a descendant of (or equal to)
628        // any UID in `rhs`
629        Ok(false.into())
630    }
631
632    /// Evaluation of conditionals
633    /// Must be sure to respect short-circuiting semantics
634    fn eval_if(
635        &self,
636        guard: &Expr,
637        consequent: &Expr,
638        alternative: &Expr,
639        slots: &SlotEnv,
640    ) -> Result<PartialValue> {
641        match self.partial_interpret(guard, slots)? {
642            PartialValue::Value(v) => {
643                if v.get_as_bool()? {
644                    self.partial_interpret(consequent, slots)
645                } else {
646                    self.partial_interpret(alternative, slots)
647                }
648            }
649            PartialValue::Residual(_) => {
650                let (consequent, consequent_errored) = self.run_to_error(consequent, slots);
651                let (alternative, alternative_errored) = self.run_to_error(alternative, slots);
652                // If both branches errored, the expression will always error
653                match (consequent_errored, alternative_errored) {
654                    (Some(e), Some(_)) => Err(e),
655                    _ => Ok(Expr::ite(guard.clone(), consequent.into(), alternative.into()).into()),
656                }
657            }
658        }
659    }
660
661    fn get_attr(&self, expr: &Expr, attr: &SmolStr, slots: &SlotEnv) -> Result<PartialValue> {
662        match self.partial_interpret(expr, slots)? {
663            // PE Cases
664            PartialValue::Residual(e) => {
665                match e.expr_kind() {
666                    ExprKind::Record { pairs } => {
667                        // If we have a residual record, we evaluate as follows:
668                        // 1) If it's safe to project, we can project. We can evaluate to see if this attribute can become a value
669                        // 2) If it's not safe to project, we can check to see if the requested key exists in the record
670                        //    if it doens't, we can fail early
671                        if e.is_projectable() {
672                            pairs
673                                .as_ref()
674                                .iter()
675                                .filter_map(|(k, v)| if k == attr { Some(v) } else { None })
676                                .next()
677                                .ok_or_else(|| {
678                                    EvaluationError::RecordAttrDoesNotExist(attr.clone())
679                                })
680                                .and_then(|e| self.partial_interpret(e, slots))
681                        } else if pairs.iter().any(|(k, _v)| k == attr) {
682                            Ok(PartialValue::Residual(Expr::get_attr(
683                                Expr::record(pairs.as_ref().clone()), // We should try to avoid this copy
684                                attr.clone(),
685                            )))
686                        } else {
687                            Err(EvaluationError::RecordAttrDoesNotExist(attr.clone()))
688                        }
689                    }
690                    // We got a residual, that is not a record at the top level
691                    _ => Ok(PartialValue::Residual(Expr::get_attr(e, attr.clone()))),
692                }
693            }
694            PartialValue::Value(Value::Record(attrs)) => attrs
695                .as_ref()
696                .get(attr)
697                .ok_or_else(|| EvaluationError::RecordAttrDoesNotExist(attr.clone()))
698                .map(|v| PartialValue::Value(v.clone())),
699            PartialValue::Value(Value::Lit(Literal::EntityUID(uid))) => {
700                match self.entity_attr_values.get(uid.as_ref()) {
701                    Dereference::NoSuchEntity => Err(match *uid.entity_type() {
702                        EntityType::Unspecified => {
703                            EvaluationError::UnspecifiedEntityAccess(attr.clone())
704                        }
705                        EntityType::Concrete(_) => EvaluationError::EntityDoesNotExist(uid.clone()),
706                    }),
707                    Dereference::Residual(r) => {
708                        Ok(PartialValue::Residual(Expr::get_attr(r, attr.clone())))
709                    }
710                    Dereference::Data(attrs) => attrs
711                        .get(attr)
712                        .ok_or_else(|| EvaluationError::EntityAttrDoesNotExist {
713                            entity: uid,
714                            attr: attr.clone(),
715                        })
716                        .cloned(),
717                }
718            }
719            PartialValue::Value(v) => Err(EvaluationError::TypeError {
720                expected: vec![
721                    Type::Record,
722                    Type::entity_type(Name::parse_unqualified_name("any_entity_type").unwrap()),
723                ],
724                actual: v.type_of(),
725            }),
726        }
727    }
728
729    #[cfg(test)]
730    pub fn interpret_inline_policy(&self, e: &Expr) -> Result<Value> {
731        match self.partial_interpret(e, &HashMap::new())? {
732            PartialValue::Value(v) => Ok(v),
733            PartialValue::Residual(r) => Err(err::EvaluationError::NonValue(r)),
734        }
735    }
736
737    /// Evaluate an expression, potentially leaving a residual
738    #[cfg(test)]
739    pub fn partial_eval_expr(&self, p: &Expr) -> Result<Either<Value, Expr>> {
740        let env = SlotEnv::new();
741        match self.partial_interpret(p, &env)? {
742            PartialValue::Value(v) => Ok(Either::Left(v)),
743            PartialValue::Residual(r) => Ok(Either::Right(r)),
744        }
745    }
746    // by default, Coverlay does not track coverage for lines after a line
747    // containing #[cfg(test)].
748    // we use the following sentinel to "turn back on" coverage tracking for
749    // remaining lines of this file, until the next #[cfg(test)]
750    // GRCOV_BEGIN_COVERAGE
751}
752
753impl<'e> std::fmt::Debug for Evaluator<'e> {
754    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
755        write!(
756            f,
757            "<Evaluator with principal = {:?}, action = {:?}, resource = {:?}",
758            &self.principal, &self.action, &self.resource
759        )
760    }
761}
762
763impl Value {
764    /// Convert the `Value` to a boolean, or throw a type error if it's not a
765    /// boolean.
766    pub(crate) fn get_as_bool(&self) -> Result<bool> {
767        match self {
768            Value::Lit(Literal::Bool(b)) => Ok(*b),
769            _ => Err(EvaluationError::TypeError {
770                expected: vec![Type::Bool],
771                actual: self.type_of(),
772            }),
773        }
774    }
775
776    /// Convert the `Value` to a Long, or throw a type error if it's not a
777    /// Long.
778    pub(crate) fn get_as_long(&self) -> Result<i64> {
779        match self {
780            Value::Lit(Literal::Long(i)) => Ok(*i),
781            _ => Err(EvaluationError::TypeError {
782                expected: vec![Type::Long],
783                actual: self.type_of(),
784            }),
785        }
786    }
787
788    /// Convert the `Value` to a String, or throw a type error if it's not a
789    /// String.
790    pub(crate) fn get_as_string(&self) -> Result<&SmolStr> {
791        match self {
792            Value::Lit(Literal::String(s)) => Ok(s),
793            _ => Err(EvaluationError::TypeError {
794                expected: vec![Type::String],
795                actual: self.type_of(),
796            }),
797        }
798    }
799
800    /// Convert the `Value` to a Set, or throw a type error if it's not a Set.
801    pub(crate) fn get_as_set(&self) -> Result<&Set> {
802        match self {
803            Value::Set(s) => Ok(s),
804            _ => Err(EvaluationError::TypeError {
805                expected: vec![Type::Set],
806                actual: self.type_of(),
807            }),
808        }
809    }
810
811    /// Convert the `Value` to an Entity, or throw a type error if it's not a
812    /// Entity.
813    pub(crate) fn get_as_entity(&self) -> Result<&EntityUID> {
814        match self {
815            Value::Lit(Literal::EntityUID(uid)) => Ok(uid.as_ref()),
816            _ => Err(EvaluationError::TypeError {
817                expected: vec![Type::entity_type(
818                    Name::parse_unqualified_name("any_entity_type").expect("valid identifier"),
819                )],
820                actual: self.type_of(),
821            }),
822        }
823    }
824}
825
826#[inline(always)]
827fn stack_size_check() -> Result<()> {
828    #[cfg(not(target_arch = "wasm32"))]
829    {
830        if stacker::remaining_stack().unwrap_or(0) < REQUIRED_STACK_SPACE {
831            return Err(EvaluationError::RecursionLimit);
832        }
833    }
834    Ok(())
835}
836
837#[cfg(test)]
838pub mod test {
839    use std::str::FromStr;
840
841    use super::*;
842
843    use crate::{
844        entities::{EntityJsonParser, TCComputation},
845        parser::{self, parse_policyset},
846        parser::{parse_expr, parse_policy_template},
847    };
848
849    // Many of these tests use this Request
850    pub fn basic_request() -> Request {
851        Request::new(
852            EntityUID::with_eid("test_principal"),
853            EntityUID::with_eid("test_action"),
854            EntityUID::with_eid("test_resource"),
855            Context::from_pairs([
856                ("cur_time".into(), RestrictedExpr::val("03:22:11")),
857                (
858                    "device_properties".into(),
859                    RestrictedExpr::record(vec![
860                        ("os_name".into(), RestrictedExpr::val("Windows")),
861                        ("manufacturer".into(), RestrictedExpr::val("ACME Corp")),
862                    ]),
863                ),
864            ]),
865        )
866    }
867
868    // Many of these tests use this basic `Entities`
869    pub fn basic_entities() -> Entities {
870        Entities::from_entities(
871            vec![
872                Entity::with_uid(EntityUID::with_eid("foo")),
873                Entity::with_uid(EntityUID::with_eid("test_principal")),
874                Entity::with_uid(EntityUID::with_eid("test_action")),
875                Entity::with_uid(EntityUID::with_eid("test_resource")),
876            ],
877            TCComputation::ComputeNow,
878        )
879        .expect("failed to create basic entities")
880    }
881
882    // This `Entities` has richer Entities
883    pub fn rich_entities() -> Entities {
884        let entity_no_attrs_no_parents =
885            Entity::with_uid(EntityUID::with_eid("entity_no_attrs_no_parents"));
886        let mut entity_with_attrs = Entity::with_uid(EntityUID::with_eid("entity_with_attrs"));
887        entity_with_attrs.set_attr("spoon".into(), RestrictedExpr::val(787));
888        entity_with_attrs.set_attr(
889            "tags".into(),
890            RestrictedExpr::set(vec![
891                RestrictedExpr::val("fun"),
892                RestrictedExpr::val("good"),
893                RestrictedExpr::val("useful"),
894            ]),
895        );
896        entity_with_attrs.set_attr(
897            "address".into(),
898            RestrictedExpr::record(vec![
899                ("street".into(), RestrictedExpr::val("234 magnolia")),
900                ("town".into(), RestrictedExpr::val("barmstadt")),
901                ("country".into(), RestrictedExpr::val("amazonia")),
902            ]),
903        );
904        let mut child = Entity::with_uid(EntityUID::with_eid("child"));
905        let mut parent = Entity::with_uid(EntityUID::with_eid("parent"));
906        let grandparent = Entity::with_uid(EntityUID::with_eid("grandparent"));
907        let mut sibling = Entity::with_uid(EntityUID::with_eid("sibling"));
908        let unrelated = Entity::with_uid(EntityUID::with_eid("unrelated"));
909        child.add_ancestor(parent.uid());
910        sibling.add_ancestor(parent.uid());
911        parent.add_ancestor(grandparent.uid());
912        let mut child_diff_type = Entity::with_uid(
913            EntityUID::with_eid_and_type("other_type", "other_child")
914                .expect("should be a valid identifier"),
915        );
916        child_diff_type.add_ancestor(parent.uid());
917        child_diff_type.add_ancestor(grandparent.uid());
918        Entities::from_entities(
919            vec![
920                entity_no_attrs_no_parents,
921                entity_with_attrs,
922                child,
923                child_diff_type,
924                parent,
925                grandparent,
926                sibling,
927                unrelated,
928            ],
929            TCComputation::ComputeNow,
930        )
931        .expect("Failed to create rich entities")
932    }
933
934    #[test]
935    fn partial_entity_stores_in_set() {
936        let q = basic_request();
937        let entities = rich_entities().partial();
938        let exts = Extensions::none();
939        let child = EntityUID::with_eid("child");
940        let second = EntityUID::with_eid("joseph");
941        let missing = EntityUID::with_eid("non-present");
942        let parent = EntityUID::with_eid("parent");
943        let eval = Evaluator::new(&q, &entities, &exts).unwrap();
944
945        let e = Expr::binary_app(
946            BinaryOp::In,
947            Expr::val(child),
948            Expr::set([Expr::val(parent.clone()), Expr::val(second.clone())]),
949        );
950        let r = eval.partial_eval_expr(&e).unwrap();
951        assert_eq!(r, Either::Left(true.into()));
952
953        let e = Expr::binary_app(
954            BinaryOp::In,
955            Expr::val(missing.clone()),
956            Expr::set([Expr::val(parent.clone()), Expr::val(second.clone())]),
957        );
958        let r = eval.partial_eval_expr(&e).unwrap();
959        let expected_residual = Expr::binary_app(
960            BinaryOp::In,
961            Expr::unknown(format!("{missing}")),
962            Expr::set([Expr::val(parent.clone()), Expr::val(second.clone())]),
963        );
964        let expected_residual2 = Expr::binary_app(
965            BinaryOp::In,
966            Expr::unknown(format!("{missing}")),
967            Expr::set([Expr::val(second), Expr::val(parent)]),
968        );
969
970        // Either ordering is valid
971        assert!(r == Either::Right(expected_residual) || r == Either::Right(expected_residual2));
972    }
973
974    #[test]
975    fn partial_entity_stores_in() {
976        let q = basic_request();
977        let entities = rich_entities().partial();
978        let exts = Extensions::none();
979        let child = EntityUID::with_eid("child");
980        let missing = EntityUID::with_eid("non-present");
981        let parent = EntityUID::with_eid("parent");
982        let eval = Evaluator::new(&q, &entities, &exts).unwrap();
983
984        let e = Expr::binary_app(BinaryOp::In, Expr::val(child), Expr::val(parent.clone()));
985        let r = eval.partial_eval_expr(&e).unwrap();
986        assert_eq!(r, Either::Left(true.into()));
987
988        let e = Expr::binary_app(
989            BinaryOp::In,
990            Expr::val(missing.clone()),
991            Expr::val(parent.clone()),
992        );
993        let r = eval.partial_eval_expr(&e).unwrap();
994        let expected_residual = Expr::binary_app(
995            BinaryOp::In,
996            Expr::unknown(format!("{missing}")),
997            Expr::val(parent),
998        );
999        assert_eq!(r, Either::Right(expected_residual));
1000    }
1001
1002    #[test]
1003    fn partial_entity_stores_hasattr() {
1004        let q = basic_request();
1005        let entities = rich_entities().partial();
1006        let exts = Extensions::none();
1007        let has_attr = EntityUID::with_eid("entity_with_attrs");
1008        let missing = EntityUID::with_eid("missing");
1009        let eval = Evaluator::new(&q, &entities, &exts).unwrap();
1010
1011        let e = Expr::has_attr(Expr::val(has_attr), "spoon".into());
1012        let r = eval.partial_eval_expr(&e).unwrap();
1013        assert_eq!(r, Either::Left(true.into()));
1014
1015        let e = Expr::has_attr(Expr::val(missing.clone()), "spoon".into());
1016        let r = eval.partial_eval_expr(&e).unwrap();
1017        let expected_residual = Expr::has_attr(Expr::unknown(format!("{missing}")), "spoon".into());
1018        assert_eq!(r, Either::Right(expected_residual));
1019    }
1020
1021    #[test]
1022    fn partial_entity_stores_getattr() {
1023        let q = basic_request();
1024        let entities = rich_entities().partial();
1025        let exts = Extensions::none();
1026        let has_attr = EntityUID::with_eid("entity_with_attrs");
1027        let missing = EntityUID::with_eid("missing");
1028        let eval = Evaluator::new(&q, &entities, &exts).unwrap();
1029
1030        let e = Expr::get_attr(Expr::val(has_attr), "spoon".into());
1031        let r = eval.partial_eval_expr(&e).unwrap();
1032        assert_eq!(r, Either::Left(787.into()));
1033
1034        let e = Expr::get_attr(Expr::val(missing.clone()), "spoon".into());
1035        let r = eval.partial_eval_expr(&e).unwrap();
1036        let expected_residual = Expr::get_attr(Expr::unknown(format!("{missing}")), "spoon".into());
1037        assert_eq!(r, Either::Right(expected_residual));
1038    }
1039
1040    #[test]
1041    fn interpret_primitives() {
1042        let request = basic_request();
1043        let entities = basic_entities();
1044        let exts = Extensions::none();
1045        let eval = Evaluator::new(&request, &entities, &exts).expect("failed to create evaluator");
1046        assert_eq!(
1047            eval.interpret_inline_policy(&Expr::val(false)),
1048            Ok(Value::Lit(Literal::Bool(false)))
1049        );
1050        assert_eq!(
1051            eval.interpret_inline_policy(&Expr::val(true)),
1052            Ok(Value::Lit(Literal::Bool(true)))
1053        );
1054        assert_eq!(
1055            eval.interpret_inline_policy(&Expr::val(57)),
1056            Ok(Value::Lit(Literal::Long(57)))
1057        );
1058        assert_eq!(
1059            eval.interpret_inline_policy(&Expr::val(-3)),
1060            Ok(Value::Lit(Literal::Long(-3)))
1061        );
1062        assert_eq!(
1063            eval.interpret_inline_policy(&Expr::val("")),
1064            Ok(Value::Lit(Literal::String("".into())))
1065        );
1066        assert_eq!(
1067            eval.interpret_inline_policy(&Expr::val("Hello")),
1068            Ok(Value::Lit(Literal::String("Hello".into())))
1069        );
1070    }
1071
1072    #[test]
1073    fn interpret_entities() {
1074        let request = basic_request();
1075        let entities = basic_entities();
1076        let exts = Extensions::none();
1077        let eval = Evaluator::new(&request, &entities, &exts).expect("failed to create evaluator");
1078        assert_eq!(
1079            eval.interpret_inline_policy(&Expr::val(EntityUID::with_eid("foo"))),
1080            Ok(Value::Lit(Literal::EntityUID(Arc::new(
1081                EntityUID::with_eid("foo")
1082            ))))
1083        );
1084        // should be no error here even for entities that do not exist.
1085        // (for instance, A == B is allowed even when A and/or B do not exist.)
1086        assert_eq!(
1087            eval.interpret_inline_policy(&Expr::val(EntityUID::with_eid("doesnotexist"))),
1088            Ok(Value::Lit(Literal::EntityUID(Arc::new(
1089                EntityUID::with_eid("doesnotexist")
1090            ))))
1091        );
1092        // unspecified entities should not result in an error.
1093        assert_eq!(
1094            eval.interpret_inline_policy(&Expr::val(EntityUID::unspecified_from_eid(Eid::new(
1095                "foo"
1096            )))),
1097            Ok(Value::Lit(Literal::EntityUID(Arc::new(
1098                EntityUID::unspecified_from_eid(Eid::new("foo"))
1099            ))))
1100        );
1101    }
1102
1103    #[test]
1104    fn interpret_builtin_vars() {
1105        let request = basic_request();
1106        let entities = basic_entities();
1107        let exts = Extensions::none();
1108        let eval = Evaluator::new(&request, &entities, &exts).expect("failed to create evaluator");
1109        assert_eq!(
1110            eval.interpret_inline_policy(&Expr::var(Var::Principal)),
1111            Ok(Value::Lit(Literal::EntityUID(Arc::new(
1112                EntityUID::with_eid("test_principal")
1113            ))))
1114        );
1115        assert_eq!(
1116            eval.interpret_inline_policy(&Expr::var(Var::Action)),
1117            Ok(Value::Lit(Literal::EntityUID(Arc::new(
1118                EntityUID::with_eid("test_action")
1119            ))))
1120        );
1121        assert_eq!(
1122            eval.interpret_inline_policy(&Expr::var(Var::Resource)),
1123            Ok(Value::Lit(Literal::EntityUID(Arc::new(
1124                EntityUID::with_eid("test_resource")
1125            ))))
1126        );
1127    }
1128
1129    #[test]
1130    fn interpret_entity_attrs() {
1131        let request = basic_request();
1132        let entities = rich_entities();
1133        let exts = Extensions::none();
1134        let eval = Evaluator::new(&request, &entities, &exts).expect("failed to create evaluator");
1135        // has_attr on an entity with no attrs
1136        assert_eq!(
1137            eval.interpret_inline_policy(&Expr::has_attr(
1138                Expr::val(EntityUID::with_eid("entity_no_attrs_no_parents")),
1139                "doesnotexist".into()
1140            )),
1141            Ok(Value::Lit(Literal::Bool(false)))
1142        );
1143        // has_attr on an entity that has attrs, but not that one
1144        assert_eq!(
1145            eval.interpret_inline_policy(&Expr::has_attr(
1146                Expr::val(EntityUID::with_eid("entity_with_attrs")),
1147                "doesnotexist".into()
1148            )),
1149            Ok(Value::Lit(Literal::Bool(false)))
1150        );
1151        // has_attr where the response is true
1152        assert_eq!(
1153            eval.interpret_inline_policy(&Expr::has_attr(
1154                Expr::val(EntityUID::with_eid("entity_with_attrs")),
1155                "tags".into()
1156            )),
1157            Ok(Value::Lit(Literal::Bool(true)))
1158        );
1159        // get_attr on an attr which doesn't exist
1160        assert_eq!(
1161            eval.interpret_inline_policy(&Expr::get_attr(
1162                Expr::val(EntityUID::with_eid("entity_with_attrs")),
1163                "doesnotexist".into()
1164            )),
1165            Err(EvaluationError::EntityAttrDoesNotExist {
1166                entity: Arc::new(EntityUID::with_eid("entity_with_attrs")),
1167                attr: "doesnotexist".into()
1168            })
1169        );
1170        // get_attr on an attr which does exist (and has integer type)
1171        assert_eq!(
1172            eval.interpret_inline_policy(&Expr::get_attr(
1173                Expr::val(EntityUID::with_eid("entity_with_attrs")),
1174                "spoon".into()
1175            )),
1176            Ok(Value::Lit(Literal::Long(787)))
1177        );
1178        // get_attr on an attr which does exist (and has Set type)
1179        assert_eq!(
1180            eval.interpret_inline_policy(&Expr::contains(
1181                Expr::get_attr(
1182                    Expr::val(EntityUID::with_eid("entity_with_attrs")),
1183                    "tags".into()
1184                ),
1185                Expr::val("useful")
1186            )),
1187            Ok(Value::from(true))
1188        );
1189        // has_attr on an entity which doesn't exist
1190        assert_eq!(
1191            eval.interpret_inline_policy(&Expr::has_attr(
1192                Expr::val(EntityUID::with_eid("doesnotexist")),
1193                "foo".into()
1194            )),
1195            Ok(Value::from(false))
1196        );
1197        // get_attr on an entity which doesn't exist
1198        assert_eq!(
1199            eval.interpret_inline_policy(&Expr::get_attr(
1200                Expr::val(EntityUID::with_eid("doesnotexist")),
1201                "foo".into()
1202            )),
1203            Err(EvaluationError::EntityDoesNotExist(Arc::new(
1204                EntityUID::with_eid("doesnotexist")
1205            )))
1206        );
1207        // has_attr on an unspecified entity
1208        assert_eq!(
1209            eval.interpret_inline_policy(&Expr::has_attr(
1210                Expr::val(EntityUID::unspecified_from_eid(Eid::new("foo"))),
1211                "foo".into()
1212            )),
1213            Ok(Value::from(false))
1214        );
1215        // get_attr on an unspecified entity
1216        assert_eq!(
1217            eval.interpret_inline_policy(&Expr::get_attr(
1218                Expr::val(EntityUID::unspecified_from_eid(Eid::new("foo"))),
1219                "bar".into()
1220            )),
1221            Err(EvaluationError::UnspecifiedEntityAccess("bar".into()))
1222        );
1223    }
1224
1225    #[test]
1226    fn interpret_ternaries() {
1227        let request = basic_request();
1228        let entities = basic_entities();
1229        let exts = Extensions::none();
1230        let eval = Evaluator::new(&request, &entities, &exts).expect("failed to create evaluator");
1231        // if true then 3 else 8
1232        assert_eq!(
1233            eval.interpret_inline_policy(&Expr::ite(Expr::val(true), Expr::val(3), Expr::val(8))),
1234            Ok(Value::Lit(Literal::Long(3)))
1235        );
1236        // if false then 3 else 8
1237        assert_eq!(
1238            eval.interpret_inline_policy(&Expr::ite(Expr::val(false), Expr::val(3), Expr::val(8))),
1239            Ok(Value::Lit(Literal::Long(8)))
1240        );
1241        // if false then false else true
1242        assert_eq!(
1243            eval.interpret_inline_policy(&Expr::ite(
1244                Expr::val(false),
1245                Expr::val(false),
1246                Expr::val(true)
1247            )),
1248            Ok(Value::Lit(Literal::Bool(true)))
1249        );
1250        // if false then principal else resource
1251        assert_eq!(
1252            eval.interpret_inline_policy(&Expr::ite(
1253                Expr::val(false),
1254                Expr::var(Var::Principal),
1255                Expr::var(Var::Resource)
1256            )),
1257            Ok(Value::from(EntityUID::with_eid("test_resource")))
1258        );
1259        // if "hello" then 3 else 8
1260        assert_eq!(
1261            eval.interpret_inline_policy(&Expr::ite(
1262                Expr::val("hello"),
1263                Expr::val(3),
1264                Expr::val(8)
1265            )),
1266            Err(EvaluationError::TypeError {
1267                expected: vec![Type::Bool],
1268                actual: Type::String
1269            })
1270        );
1271        // if principal then 3 else 8
1272        assert_eq!(
1273            eval.interpret_inline_policy(&Expr::ite(
1274                Expr::var(Var::Principal),
1275                Expr::val(3),
1276                Expr::val(8)
1277            )),
1278            Err(EvaluationError::TypeError {
1279                expected: vec![Type::Bool],
1280                actual: Type::Entity {
1281                    ty: EntityUID::test_entity_type(),
1282                }
1283            })
1284        );
1285        // if true then "hello" else 2
1286        assert_eq!(
1287            eval.interpret_inline_policy(&Expr::ite(
1288                Expr::val(true),
1289                Expr::val("hello"),
1290                Expr::val(2)
1291            )),
1292            Ok(Value::from("hello"))
1293        );
1294        // if false then "hello" else 2
1295        assert_eq!(
1296            eval.interpret_inline_policy(&Expr::ite(
1297                Expr::val(false),
1298                Expr::val("hello"),
1299                Expr::val(2)
1300            )),
1301            Ok(Value::Lit(Literal::Long(2)))
1302        );
1303        // if true then (if true then 3 else 8) else -10
1304        assert_eq!(
1305            eval.interpret_inline_policy(&Expr::ite(
1306                Expr::val(true),
1307                Expr::ite(Expr::val(true), Expr::val(3), Expr::val(8)),
1308                Expr::val(-10)
1309            )),
1310            Ok(Value::Lit(Literal::Long(3)))
1311        );
1312        // if true then (if false then 3 else 8) else -10
1313        assert_eq!(
1314            eval.interpret_inline_policy(&Expr::ite(
1315                Expr::val(true),
1316                Expr::ite(Expr::val(false), Expr::val(3), Expr::val(8)),
1317                Expr::val(-10)
1318            )),
1319            Ok(Value::Lit(Literal::Long(8)))
1320        );
1321        // if false then (if false then 3 else 8) else -10
1322        assert_eq!(
1323            eval.interpret_inline_policy(&Expr::ite(
1324                Expr::val(false),
1325                Expr::ite(Expr::val(false), Expr::val(3), Expr::val(8)),
1326                Expr::val(-10)
1327            )),
1328            Ok(Value::Lit(Literal::Long(-10)))
1329        );
1330        // if false then (if "hello" then 3 else 8) else -10
1331        assert_eq!(
1332            eval.interpret_inline_policy(&Expr::ite(
1333                Expr::val(false),
1334                Expr::ite(Expr::val("hello"), Expr::val(3), Expr::val(8)),
1335                Expr::val(-10)
1336            )),
1337            Ok(Value::Lit(Literal::Long(-10)))
1338        );
1339        // if true then 3 else (if true then 8 else -10)
1340        assert_eq!(
1341            eval.interpret_inline_policy(&Expr::ite(
1342                Expr::val(true),
1343                Expr::val(3),
1344                Expr::ite(Expr::val(true), Expr::val(8), Expr::val(-10))
1345            )),
1346            Ok(Value::Lit(Literal::Long(3)))
1347        );
1348        // if (if true then false else true) then 3 else 8
1349        assert_eq!(
1350            eval.interpret_inline_policy(&Expr::ite(
1351                Expr::ite(Expr::val(true), Expr::val(false), Expr::val(true)),
1352                Expr::val(3),
1353                Expr::val(8)
1354            )),
1355            Ok(Value::Lit(Literal::Long(8)))
1356        );
1357        // if true then 3 else <err>
1358        assert_eq!(
1359            eval.interpret_inline_policy(&Expr::ite(
1360                Expr::val(true),
1361                Expr::val(3),
1362                Expr::get_attr(Expr::record(vec![]), "foo".into()),
1363            )),
1364            Ok(Value::Lit(Literal::Long(3)))
1365        );
1366        // if false then 3 else <err>
1367        assert_eq!(
1368            eval.interpret_inline_policy(&Expr::ite(
1369                Expr::val(false),
1370                Expr::val(3),
1371                Expr::get_attr(Expr::record(vec![]), "foo".into()),
1372            )),
1373            Err(EvaluationError::RecordAttrDoesNotExist("foo".into()))
1374        );
1375        // if true then <err> else 3
1376        assert_eq!(
1377            eval.interpret_inline_policy(&Expr::ite(
1378                Expr::val(true),
1379                Expr::get_attr(Expr::record(vec![]), "foo".into()),
1380                Expr::val(3),
1381            )),
1382            Err(EvaluationError::RecordAttrDoesNotExist("foo".into()))
1383        );
1384        // if false then <err> else 3
1385        assert_eq!(
1386            eval.interpret_inline_policy(&Expr::ite(
1387                Expr::val(false),
1388                Expr::get_attr(Expr::record(vec![]), "foo".into()),
1389                Expr::val(3),
1390            )),
1391            Ok(Value::Lit(Literal::Long(3)))
1392        );
1393    }
1394
1395    #[test]
1396    fn interpret_sets() {
1397        let request = basic_request();
1398        let entities = basic_entities();
1399        let exts = Extensions::none();
1400        let eval = Evaluator::new(&request, &entities, &exts).expect("failed to create evaluator");
1401        // set(8)
1402        assert_eq!(
1403            eval.interpret_inline_policy(&Expr::set(vec![Expr::val(8)])),
1404            Ok(Value::set(vec![Value::Lit(Literal::Long(8))]))
1405        );
1406        // set(8, 2, 101)
1407        assert_eq!(
1408            eval.interpret_inline_policy(&Expr::set(vec![
1409                Expr::val(8),
1410                Expr::val(2),
1411                Expr::val(101)
1412            ])),
1413            Ok(Value::set(vec![
1414                Value::Lit(Literal::Long(8)),
1415                Value::Lit(Literal::Long(2)),
1416                Value::Lit(Literal::Long(101))
1417            ]))
1418        );
1419        // empty set
1420        assert_eq!(
1421            eval.interpret_inline_policy(&Expr::set(vec![])),
1422            Ok(Value::empty_set())
1423        );
1424        assert_eq!(
1425            eval.interpret_inline_policy(&Expr::set(vec![])),
1426            Ok(Value::empty_set())
1427        );
1428        // set(8)["hello"]
1429        assert_eq!(
1430            eval.interpret_inline_policy(&Expr::get_attr(
1431                Expr::set(vec![Expr::val(8)]),
1432                "hello".into()
1433            )),
1434            Err(EvaluationError::TypeError {
1435                expected: vec![
1436                    Type::Record,
1437                    Type::entity_type(
1438                        Name::parse_unqualified_name("any_entity_type")
1439                            .expect("should be a valid identifier")
1440                    ),
1441                ],
1442                actual: Type::Set,
1443            })
1444        );
1445        // indexing into empty set
1446        assert_eq!(
1447            eval.interpret_inline_policy(&Expr::get_attr(Expr::set(vec![]), "hello".into())),
1448            Err(EvaluationError::TypeError {
1449                expected: vec![
1450                    Type::Record,
1451                    Type::entity_type(
1452                        Name::parse_unqualified_name("any_entity_type")
1453                            .expect("should be a valid identifier")
1454                    ),
1455                ],
1456                actual: Type::Set,
1457            })
1458        );
1459        // set("hello", 2, true, <entity foo>)
1460        let mixed_set = Expr::set(vec![
1461            Expr::val("hello"),
1462            Expr::val(2),
1463            Expr::val(true),
1464            Expr::val(EntityUID::with_eid("foo")),
1465        ]);
1466        assert_eq!(
1467            eval.interpret_inline_policy(&mixed_set),
1468            Ok(Value::set(vec![
1469                Value::Lit(Literal::String("hello".into())),
1470                Value::Lit(Literal::Long(2)),
1471                Value::Lit(Literal::Bool(true)),
1472                Value::Lit(Literal::EntityUID(Arc::new(EntityUID::with_eid("foo")))),
1473            ]))
1474        );
1475        // set("hello", 2, true, <entity foo>)["hello"]
1476        assert_eq!(
1477            eval.interpret_inline_policy(&Expr::get_attr(mixed_set, "hello".into())),
1478            Err(EvaluationError::TypeError {
1479                expected: vec![
1480                    Type::Record,
1481                    Type::entity_type(
1482                        Name::parse_unqualified_name("any_entity_type")
1483                            .expect("should be a valid identifier")
1484                    ),
1485                ],
1486                actual: Type::Set
1487            })
1488        );
1489        // set(set(8, 2), set(13, 702), set(3))
1490        let set_of_sets = Expr::set(vec![
1491            Expr::set(vec![Expr::val(8), Expr::val(2)]),
1492            Expr::set(vec![Expr::val(13), Expr::val(702)]),
1493            Expr::set(vec![Expr::val(3)]),
1494        ]);
1495        assert_eq!(
1496            eval.interpret_inline_policy(&set_of_sets),
1497            Ok(Value::set(vec![
1498                Value::set(vec![
1499                    Value::Lit(Literal::Long(8)),
1500                    Value::Lit(Literal::Long(2))
1501                ]),
1502                Value::set(vec![
1503                    Value::Lit(Literal::Long(13)),
1504                    Value::Lit(Literal::Long(702))
1505                ]),
1506                Value::set(vec![Value::Lit(Literal::Long(3))]),
1507            ]))
1508        );
1509        // set(set(8, 2), set(13, 702), set(3))["hello"]
1510        assert_eq!(
1511            eval.interpret_inline_policy(&Expr::get_attr(set_of_sets.clone(), "hello".into())),
1512            Err(EvaluationError::TypeError {
1513                expected: vec![
1514                    Type::Record,
1515                    Type::entity_type(
1516                        Name::parse_unqualified_name("any_entity_type")
1517                            .expect("should be a valid identifier")
1518                    ),
1519                ],
1520                actual: Type::Set
1521            })
1522        );
1523        // set(set(8, 2), set(13, 702), set(3))["ham"]["eggs"]
1524        assert_eq!(
1525            eval.interpret_inline_policy(&Expr::get_attr(
1526                Expr::get_attr(set_of_sets, "ham".into()),
1527                "eggs".into()
1528            )),
1529            Err(EvaluationError::TypeError {
1530                expected: vec![
1531                    Type::Record,
1532                    Type::entity_type(
1533                        Name::parse_unqualified_name("any_entity_type")
1534                            .expect("should be a valid identifier")
1535                    ),
1536                ],
1537                actual: Type::Set
1538            })
1539        );
1540    }
1541
1542    #[test]
1543    fn interpret_records() {
1544        let request = basic_request();
1545        let entities = rich_entities();
1546        let exts = Extensions::none();
1547        let eval = Evaluator::new(&request, &entities, &exts).expect("failed to create evaluator");
1548        // {"key": 3}["key"] or {"key": 3}.key
1549        let string_key = Expr::record(vec![("key".into(), Expr::val(3))]);
1550        assert_eq!(
1551            eval.interpret_inline_policy(&Expr::get_attr(string_key, "key".into())),
1552            Ok(Value::Lit(Literal::Long(3)))
1553        );
1554        // {"ham": 3, "eggs": 7}["ham"] or {"ham": 3, "eggs": 7}.ham
1555        let ham_and_eggs = Expr::record(vec![
1556            ("ham".into(), Expr::val(3)),
1557            ("eggs".into(), Expr::val(7)),
1558        ]);
1559        assert_eq!(
1560            eval.interpret_inline_policy(&Expr::get_attr(ham_and_eggs.clone(), "ham".into())),
1561            Ok(Value::Lit(Literal::Long(3)))
1562        );
1563        // {"ham": 3, "eggs": 7}["eggs"]
1564        assert_eq!(
1565            eval.interpret_inline_policy(&Expr::get_attr(ham_and_eggs.clone(), "eggs".into())),
1566            Ok(Value::Lit(Literal::Long(7)))
1567        );
1568        // {"ham": 3, "eggs": 7}["what"]
1569        assert_eq!(
1570            eval.interpret_inline_policy(&Expr::get_attr(ham_and_eggs, "what".into())),
1571            Err(EvaluationError::RecordAttrDoesNotExist("what".into()))
1572        );
1573
1574        // {"ham": 3, "eggs": "why"}["ham"]
1575        let ham_and_eggs_2 = Expr::record(vec![
1576            ("ham".into(), Expr::val(3)),
1577            ("eggs".into(), Expr::val("why")),
1578        ]);
1579        assert_eq!(
1580            eval.interpret_inline_policy(&Expr::get_attr(ham_and_eggs_2.clone(), "ham".into())),
1581            Ok(Value::Lit(Literal::Long(3)))
1582        );
1583        // {"ham": 3, "eggs": "why"}["eggs"]
1584        assert_eq!(
1585            eval.interpret_inline_policy(&Expr::get_attr(ham_and_eggs_2, "eggs".into())),
1586            Ok(Value::from("why"))
1587        );
1588        // {"ham": 3, "eggs": "why", "else": <entity foo>}["else"]
1589        let ham_and_eggs_3 = Expr::record(vec![
1590            ("ham".into(), Expr::val(3)),
1591            ("eggs".into(), Expr::val("why")),
1592            ("else".into(), Expr::val(EntityUID::with_eid("foo"))),
1593        ]);
1594        assert_eq!(
1595            eval.interpret_inline_policy(&Expr::get_attr(ham_and_eggs_3, "else".into())),
1596            Ok(Value::from(EntityUID::with_eid("foo")))
1597        );
1598        // {"hams": {"some": 1, "more": 2}, "eggs": "why"}["hams"]["more"]
1599        let hams_and_eggs = Expr::record(vec![
1600            (
1601                "hams".into(),
1602                Expr::record(vec![
1603                    ("some".into(), Expr::val(1)),
1604                    ("more".into(), Expr::val(2)),
1605                ]),
1606            ),
1607            ("eggs".into(), Expr::val("why")),
1608        ]);
1609        assert_eq!(
1610            eval.interpret_inline_policy(&Expr::get_attr(
1611                Expr::get_attr(hams_and_eggs, "hams".into()),
1612                "more".into()
1613            )),
1614            Ok(Value::Lit(Literal::Long(2)))
1615        );
1616        // {"this is a valid map key+.-_%() ": 7}["this is a valid map key+.-_%() "]
1617        let weird_key = Expr::record(vec![(
1618            "this is a valid map key+.-_%() ".into(),
1619            Expr::val(7),
1620        )]);
1621        assert_eq!(
1622            eval.interpret_inline_policy(&Expr::get_attr(
1623                weird_key,
1624                "this is a valid map key+.-_%() ".into()
1625            )),
1626            Ok(Value::Lit(Literal::Long(7)))
1627        );
1628        // { foo: 2, bar: [3, 33, 333] }.bar
1629        assert_eq!(
1630            eval.interpret_inline_policy(&Expr::get_attr(
1631                Expr::record(vec![
1632                    ("foo".into(), Expr::val(2)),
1633                    (
1634                        "bar".into(),
1635                        Expr::set(vec!(Expr::val(3), Expr::val(33), Expr::val(333)))
1636                    )
1637                ]),
1638                "bar".into()
1639            )),
1640            Ok(Value::set(vec![
1641                Value::from(3),
1642                Value::from(33),
1643                Value::from(333)
1644            ]))
1645        );
1646        // { foo: 2, bar: {"a+b": 5, "jkl;": 10} }.bar["a+b"]
1647        assert_eq!(
1648            eval.interpret_inline_policy(&Expr::get_attr(
1649                Expr::get_attr(
1650                    Expr::record(vec![
1651                        ("foo".into(), Expr::val(2)),
1652                        (
1653                            "bar".into(),
1654                            Expr::record(vec![
1655                                ("a+b".into(), Expr::val(5)),
1656                                ("jkl;".into(), Expr::val(10)),
1657                            ])
1658                        ),
1659                    ]),
1660                    "bar".into()
1661                ),
1662                "a+b".into()
1663            )),
1664            Ok(Value::Lit(Literal::Long(5)))
1665        );
1666        // { foo: 2, bar: { foo: 4, cake: 77 } }.bar.foo
1667        assert_eq!(
1668            eval.interpret_inline_policy(&Expr::get_attr(
1669                Expr::get_attr(
1670                    Expr::record(vec![
1671                        ("foo".into(), Expr::val(2)),
1672                        (
1673                            "bar".into(),
1674                            Expr::record(vec![
1675                                ("foo".into(), Expr::val(4)),
1676                                ("cake".into(), Expr::val(77)),
1677                            ])
1678                        ),
1679                    ]),
1680                    "bar".into(),
1681                ),
1682                "foo".into(),
1683            )),
1684            Ok(Value::Lit(Literal::Long(4)))
1685        );
1686        // entity_with_attrs.address.street
1687        assert_eq!(
1688            eval.interpret_inline_policy(&Expr::get_attr(
1689                Expr::get_attr(
1690                    Expr::val(EntityUID::with_eid("entity_with_attrs")),
1691                    "address".into()
1692                ),
1693                "street".into()
1694            )),
1695            Ok(Value::Lit(Literal::String("234 magnolia".into())))
1696        );
1697        // context.cur_time
1698        assert_eq!(
1699            eval.interpret_inline_policy(&Expr::get_attr(
1700                Expr::var(Var::Context),
1701                "cur_time".into()
1702            )),
1703            Ok(Value::Lit(Literal::String("03:22:11".into())))
1704        );
1705        // context.device_properties.os_name
1706        assert_eq!(
1707            eval.interpret_inline_policy(&Expr::get_attr(
1708                Expr::get_attr(Expr::var(Var::Context), "device_properties".into()),
1709                "os_name".into()
1710            )),
1711            Ok(Value::Lit(Literal::String("Windows".into())))
1712        );
1713        // using has() to test for existence of a record field (which does exist)
1714        // has({"foo": 77, "bar" : "pancakes"}.foo)
1715        assert_eq!(
1716            eval.interpret_inline_policy(&Expr::has_attr(
1717                Expr::record(vec![
1718                    ("foo".into(), Expr::val(77)),
1719                    ("bar".into(), Expr::val("pancakes")),
1720                ]),
1721                "foo".into()
1722            )),
1723            Ok(Value::Lit(Literal::Bool(true)))
1724        );
1725        // using has() to test for existence of a record field (which doesn't exist)
1726        // has({"foo": 77, "bar" : "pancakes"}.pancakes)
1727        assert_eq!(
1728            eval.interpret_inline_policy(&Expr::has_attr(
1729                Expr::record(vec![
1730                    ("foo".into(), Expr::val(77)),
1731                    ("bar".into(), Expr::val("pancakes")),
1732                ]),
1733                "pancakes".into()
1734            )),
1735            Ok(Value::Lit(Literal::Bool(false)))
1736        );
1737        // has({"2": "ham"}["2"])
1738        assert_eq!(
1739            eval.interpret_inline_policy(&Expr::has_attr(
1740                Expr::record(vec![("2".into(), Expr::val("ham"))]),
1741                "2".into()
1742            )),
1743            Ok(Value::Lit(Literal::Bool(true)))
1744        );
1745        // has({"ham": 17, "eggs": if has(foo.spaghetti) then 3 else 7}.ham)
1746        assert_eq!(
1747            eval.interpret_inline_policy(&Expr::has_attr(
1748                Expr::record(vec![
1749                    ("ham".into(), Expr::val(17)),
1750                    (
1751                        "eggs".into(),
1752                        Expr::ite(
1753                            Expr::has_attr(
1754                                Expr::val(EntityUID::with_eid("foo")),
1755                                "spaghetti".into()
1756                            ),
1757                            Expr::val(3),
1758                            Expr::val(7)
1759                        )
1760                    ),
1761                ]),
1762                "ham".into()
1763            )),
1764            Ok(Value::Lit(Literal::Bool(true)))
1765        );
1766        // indexing into something that's not a record, 1010122["hello"]
1767        assert_eq!(
1768            eval.interpret_inline_policy(&Expr::get_attr(Expr::val(1010122), "hello".into())),
1769            Err(EvaluationError::TypeError {
1770                expected: vec![
1771                    Type::Record,
1772                    Type::entity_type(
1773                        Name::parse_unqualified_name("any_entity_type")
1774                            .expect("should be a valid identifier")
1775                    ),
1776                ],
1777                actual: Type::Long
1778            })
1779        );
1780        // indexing into something that's not a record, "hello"["eggs"]
1781        assert_eq!(
1782            eval.interpret_inline_policy(&Expr::get_attr(Expr::val("hello"), "eggs".into())),
1783            Err(EvaluationError::TypeError {
1784                expected: vec![
1785                    Type::Record,
1786                    Type::entity_type(
1787                        Name::parse_unqualified_name("any_entity_type")
1788                            .expect("should be a valid identifier")
1789                    ),
1790                ],
1791                actual: Type::String
1792            })
1793        );
1794        // has_attr on something that's not a record, has(1010122.hello)
1795        assert_eq!(
1796            eval.interpret_inline_policy(&Expr::has_attr(Expr::val(1010122), "hello".into())),
1797            Err(EvaluationError::TypeError {
1798                expected: vec![
1799                    Type::Record,
1800                    Type::entity_type(
1801                        Name::parse_unqualified_name("any_entity_type")
1802                            .expect("should be a valid identifier")
1803                    ),
1804                ],
1805                actual: Type::Long
1806            })
1807        );
1808        // has_attr on something that's not a record, has("hello".eggs)
1809        assert_eq!(
1810            eval.interpret_inline_policy(&Expr::has_attr(Expr::val("hello"), "eggs".into())),
1811            Err(EvaluationError::TypeError {
1812                expected: vec![
1813                    Type::Record,
1814                    Type::entity_type(
1815                        Name::parse_unqualified_name("any_entity_type")
1816                            .expect("should be a valid identifier")
1817                    ),
1818                ],
1819                actual: Type::String
1820            })
1821        );
1822    }
1823
1824    #[test]
1825    fn interpret_nots() {
1826        let request = basic_request();
1827        let entities = basic_entities();
1828        let exts = Extensions::none();
1829        let eval = Evaluator::new(&request, &entities, &exts).expect("failed to create evaluator");
1830        // not(true)
1831        assert_eq!(
1832            eval.interpret_inline_policy(&Expr::not(Expr::val(true))),
1833            Ok(Value::Lit(Literal::Bool(false)))
1834        );
1835        // not(false)
1836        assert_eq!(
1837            eval.interpret_inline_policy(&Expr::not(Expr::val(false))),
1838            Ok(Value::Lit(Literal::Bool(true)))
1839        );
1840        // not(8)
1841        assert_eq!(
1842            eval.interpret_inline_policy(&Expr::not(Expr::val(8))),
1843            Err(EvaluationError::TypeError {
1844                expected: vec![Type::Bool],
1845                actual: Type::Long
1846            })
1847        );
1848        // not(action)
1849        assert_eq!(
1850            eval.interpret_inline_policy(&Expr::not(Expr::var(Var::Action))),
1851            Err(EvaluationError::TypeError {
1852                expected: vec![Type::Bool],
1853                actual: Type::Entity {
1854                    ty: EntityUID::test_entity_type(),
1855                }
1856            })
1857        );
1858        // not(not(true))
1859        assert_eq!(
1860            eval.interpret_inline_policy(&Expr::not(Expr::not(Expr::val(true)))),
1861            Ok(Value::Lit(Literal::Bool(true)))
1862        );
1863        // not(if true then false else true)
1864        assert_eq!(
1865            eval.interpret_inline_policy(&Expr::not(Expr::ite(
1866                Expr::val(true),
1867                Expr::val(false),
1868                Expr::val(true)
1869            ))),
1870            Ok(Value::Lit(Literal::Bool(true)))
1871        );
1872        // if not(true) then "hello" else "goodbye"
1873        assert_eq!(
1874            eval.interpret_inline_policy(&Expr::ite(
1875                Expr::not(Expr::val(true)),
1876                Expr::val("hello"),
1877                Expr::val("goodbye")
1878            )),
1879            Ok(Value::from("goodbye"))
1880        );
1881    }
1882
1883    #[test]
1884    fn interpret_negs() {
1885        let request = basic_request();
1886        let entities = basic_entities();
1887        let exts = Extensions::none();
1888        let eval = Evaluator::new(&request, &entities, &exts).expect("failed to create evaluator");
1889        // neg(101)
1890        assert_eq!(
1891            eval.interpret_inline_policy(&Expr::neg(Expr::val(101))),
1892            Ok(Value::Lit(Literal::Long(-101)))
1893        );
1894        // neg(-101)
1895        assert_eq!(
1896            eval.interpret_inline_policy(&Expr::neg(Expr::val(-101))),
1897            Ok(Value::Lit(Literal::Long(101)))
1898        );
1899        // neg(0)
1900        assert_eq!(
1901            eval.interpret_inline_policy(&Expr::neg(Expr::val(0))),
1902            Ok(Value::Lit(Literal::Long(0)))
1903        );
1904        // neg(neg(7))
1905        assert_eq!(
1906            eval.interpret_inline_policy(&Expr::neg(Expr::neg(Expr::val(7)))),
1907            Ok(Value::Lit(Literal::Long(7)))
1908        );
1909        // if true then neg(8) else neg(1)
1910        assert_eq!(
1911            eval.interpret_inline_policy(&Expr::ite(
1912                Expr::val(true),
1913                Expr::neg(Expr::val(8)),
1914                Expr::neg(Expr::val(1))
1915            )),
1916            Ok(Value::Lit(Literal::Long(-8)))
1917        );
1918        // overflow
1919        assert_eq!(
1920            eval.interpret_inline_policy(&Expr::neg(Expr::val(std::i64::MIN))),
1921            Err(EvaluationError::IntegerOverflow(
1922                IntegerOverflowError::UnaryOp {
1923                    op: UnaryOp::Neg,
1924                    arg: Value::from(std::i64::MIN)
1925                }
1926            )),
1927        );
1928        // neg(false)
1929        assert_eq!(
1930            eval.interpret_inline_policy(&Expr::neg(Expr::val(false))),
1931            Err(EvaluationError::TypeError {
1932                expected: vec![Type::Long],
1933                actual: Type::Bool
1934            })
1935        );
1936        // neg([1, 2, 3])
1937        assert_eq!(
1938            eval.interpret_inline_policy(&Expr::neg(Expr::set([
1939                Expr::val(1),
1940                Expr::val(2),
1941                Expr::val(3)
1942            ]))),
1943            Err(EvaluationError::TypeError {
1944                expected: vec![Type::Long],
1945                actual: Type::Set
1946            })
1947        );
1948    }
1949
1950    #[test]
1951    fn interpret_eqs() {
1952        let request = basic_request();
1953        let entities = basic_entities();
1954        let exts = Extensions::none();
1955        let eval = Evaluator::new(&request, &entities, &exts).expect("failed to create evaluator");
1956        // eq(33, 33)
1957        assert_eq!(
1958            eval.interpret_inline_policy(&Expr::is_eq(Expr::val(33), Expr::val(33))),
1959            Ok(Value::Lit(Literal::Bool(true)))
1960        );
1961        // eq(33, -12)
1962        assert_eq!(
1963            eval.interpret_inline_policy(&Expr::is_eq(Expr::val(33), Expr::val(-12))),
1964            Ok(Value::Lit(Literal::Bool(false)))
1965        );
1966        // if eq("foo", "foo") then 12 else 97
1967        assert_eq!(
1968            eval.interpret_inline_policy(&Expr::ite(
1969                Expr::is_eq(Expr::val("foo"), Expr::val("foo")),
1970                Expr::val(12),
1971                Expr::val(97),
1972            )),
1973            Ok(Value::Lit(Literal::Long(12)))
1974        );
1975        // if eq([1, -33, 707], [1, -33]) then 12 else 97
1976        assert_eq!(
1977            eval.interpret_inline_policy(&Expr::ite(
1978                Expr::is_eq(
1979                    Expr::set(vec![Expr::val(1), Expr::val(-33), Expr::val(707)]),
1980                    Expr::set(vec![Expr::val(1), Expr::val(-33)])
1981                ),
1982                Expr::val(12),
1983                Expr::val(97),
1984            )),
1985            Ok(Value::Lit(Literal::Long(97)))
1986        );
1987        // eq(2>0, 0>(-2))
1988        assert_eq!(
1989            eval.interpret_inline_policy(&Expr::is_eq(
1990                Expr::greater(Expr::val(2), Expr::val(0)),
1991                Expr::greater(Expr::val(0), Expr::val(-2))
1992            )),
1993            Ok(Value::Lit(Literal::Bool(true)))
1994        );
1995        // eq(12+33, 50-5)
1996        assert_eq!(
1997            eval.interpret_inline_policy(&Expr::is_eq(
1998                Expr::add(Expr::val(12), Expr::val(33)),
1999                Expr::sub(Expr::val(50), Expr::val(5)),
2000            )),
2001            Ok(Value::Lit(Literal::Bool(true)))
2002        );
2003        // eq([1, 2, 40], [1, 2, 40])
2004        assert_eq!(
2005            eval.interpret_inline_policy(&Expr::is_eq(
2006                Expr::set(vec![Expr::val(1), Expr::val(2), Expr::val(40)]),
2007                Expr::set(vec![Expr::val(1), Expr::val(2), Expr::val(40)])
2008            )),
2009            Ok(Value::Lit(Literal::Bool(true)))
2010        );
2011        // eq([1, 2, 40], [1, 40, 2])
2012        assert_eq!(
2013            eval.interpret_inline_policy(&Expr::is_eq(
2014                Expr::set(vec![Expr::val(1), Expr::val(2), Expr::val(40)]),
2015                Expr::set(vec![Expr::val(1), Expr::val(40), Expr::val(2)])
2016            )),
2017            Ok(Value::Lit(Literal::Bool(true)))
2018        );
2019        // eq([1, -2, 40], [1, 40])
2020        assert_eq!(
2021            eval.interpret_inline_policy(&Expr::is_eq(
2022                Expr::set(vec![Expr::val(1), Expr::val(-2), Expr::val(40)]),
2023                Expr::set(vec![Expr::val(1), Expr::val(40)])
2024            )),
2025            Ok(Value::Lit(Literal::Bool(false)))
2026        );
2027        // eq([1, 1, 1, 2, 40], [40, 1, 2])
2028        assert_eq!(
2029            eval.interpret_inline_policy(&Expr::is_eq(
2030                Expr::set(vec![
2031                    Expr::val(1),
2032                    Expr::val(1),
2033                    Expr::val(1),
2034                    Expr::val(2),
2035                    Expr::val(40)
2036                ]),
2037                Expr::set(vec![Expr::val(40), Expr::val(1), Expr::val(2)])
2038            )),
2039            Ok(Value::Lit(Literal::Bool(true)))
2040        );
2041        // eq([1, 1, 2, 1, 40, 2, 1, 2, 40, 1], [1, 40, 1, 2])
2042        assert_eq!(
2043            eval.interpret_inline_policy(&Expr::is_eq(
2044                Expr::set(vec![
2045                    Expr::val(1),
2046                    Expr::val(1),
2047                    Expr::val(2),
2048                    Expr::val(1),
2049                    Expr::val(40),
2050                    Expr::val(2),
2051                    Expr::val(1),
2052                    Expr::val(2),
2053                    Expr::val(40),
2054                    Expr::val(1)
2055                ]),
2056                Expr::set(vec![
2057                    Expr::val(1),
2058                    Expr::val(40),
2059                    Expr::val(1),
2060                    Expr::val(2)
2061                ])
2062            )),
2063            Ok(Value::Lit(Literal::Bool(true)))
2064        );
2065        // eq(context.device_properties, { appropriate record literal })
2066        assert_eq!(
2067            eval.interpret_inline_policy(&Expr::is_eq(
2068                Expr::get_attr(Expr::var(Var::Context), "device_properties".into()),
2069                Expr::record(vec![
2070                    ("os_name".into(), Expr::val("Windows")),
2071                    ("manufacturer".into(), Expr::val("ACME Corp")),
2072                ])
2073            )),
2074            Ok(Value::Lit(Literal::Bool(true)))
2075        );
2076        // eq(context.device_properties, { record literal missing one field })
2077        assert_eq!(
2078            eval.interpret_inline_policy(&Expr::is_eq(
2079                Expr::get_attr(Expr::var(Var::Context), "device_properties".into()),
2080                Expr::record(vec![("os_name".into(), Expr::val("Windows")),])
2081            )),
2082            Ok(Value::Lit(Literal::Bool(false)))
2083        );
2084        // eq(context.device_properties, { record literal with an extra field })
2085        assert_eq!(
2086            eval.interpret_inline_policy(&Expr::is_eq(
2087                Expr::get_attr(Expr::var(Var::Context), "device_properties".into()),
2088                Expr::record(vec![
2089                    ("os_name".into(), Expr::val("Windows")),
2090                    ("manufacturer".into(), Expr::val("ACME Corp")),
2091                    ("extrafield".into(), Expr::val(true)),
2092                ])
2093            )),
2094            Ok(Value::Lit(Literal::Bool(false)))
2095        );
2096        // eq(context.device_properties, { record literal with the same keys/values })
2097        assert_eq!(
2098            eval.interpret_inline_policy(&Expr::is_eq(
2099                Expr::get_attr(Expr::var(Var::Context), "device_properties".into()),
2100                Expr::record(vec![
2101                    ("os_name".into(), Expr::val("Windows")),
2102                    ("manufacturer".into(), Expr::val("ACME Corp")),
2103                ])
2104            )),
2105            Ok(Value::Lit(Literal::Bool(true)))
2106        );
2107        // eq(A, A) where A is an Entity
2108        assert_eq!(
2109            eval.interpret_inline_policy(&Expr::is_eq(
2110                Expr::val(EntityUID::with_eid("foo")),
2111                Expr::val(EntityUID::with_eid("foo")),
2112            )),
2113            Ok(Value::Lit(Literal::Bool(true)))
2114        );
2115        // eq(A, A) where A is an Entity that doesn't exist
2116        assert_eq!(
2117            eval.interpret_inline_policy(&Expr::is_eq(
2118                Expr::val(EntityUID::with_eid("doesnotexist")),
2119                Expr::val(EntityUID::with_eid("doesnotexist")),
2120            )),
2121            Ok(Value::Lit(Literal::Bool(true)))
2122        );
2123        // eq(A, B) where A and B are entities of the same type
2124        assert_eq!(
2125            eval.interpret_inline_policy(&Expr::is_eq(
2126                Expr::val(EntityUID::with_eid("foo")),
2127                Expr::val(EntityUID::with_eid("bar")),
2128            )),
2129            Ok(Value::Lit(Literal::Bool(false)))
2130        );
2131        // eq(A, B) where A and B are entities of different types
2132        assert_eq!(
2133            eval.interpret_inline_policy(&Expr::is_eq(
2134                Expr::val(
2135                    EntityUID::with_eid_and_type("type1", "foo")
2136                        .expect("should be a valid identifier")
2137                ),
2138                Expr::val(
2139                    EntityUID::with_eid_and_type("type2", "bar")
2140                        .expect("should be a valid identifier")
2141                ),
2142            )),
2143            Ok(Value::Lit(Literal::Bool(false)))
2144        );
2145        // eq(A, B) where A and B are entities of different types but happen to
2146        // have the same name
2147        assert_eq!(
2148            eval.interpret_inline_policy(&Expr::is_eq(
2149                Expr::val(
2150                    EntityUID::with_eid_and_type("type1", "foo")
2151                        .expect("should be a valid identifier")
2152                ),
2153                Expr::val(
2154                    EntityUID::with_eid_and_type("type2", "foo")
2155                        .expect("should be a valid identifier")
2156                ),
2157            )),
2158            Ok(Value::Lit(Literal::Bool(false)))
2159        );
2160        // eq(A, B) where A exists but B does not
2161        assert_eq!(
2162            eval.interpret_inline_policy(&Expr::is_eq(
2163                Expr::val(EntityUID::with_eid("foo")),
2164                Expr::val(EntityUID::with_eid("doesnotexist")),
2165            )),
2166            Ok(Value::Lit(Literal::Bool(false)))
2167        );
2168        // eq("foo", <entity foo>)
2169        assert_eq!(
2170            eval.interpret_inline_policy(&Expr::is_eq(
2171                Expr::val("foo"),
2172                Expr::val(EntityUID::with_eid("foo"))
2173            )),
2174            Ok(Value::Lit(Literal::Bool(false)))
2175        );
2176    }
2177
2178    #[test]
2179    fn interpret_compares() {
2180        let request = basic_request();
2181        let entities = basic_entities();
2182        let exts = Extensions::none();
2183        let eval = Evaluator::new(&request, &entities, &exts).expect("failed to create evaluator");
2184        // 3 < 303
2185        assert_eq!(
2186            eval.interpret_inline_policy(&Expr::less(Expr::val(3), Expr::val(303))),
2187            Ok(Value::Lit(Literal::Bool(true)))
2188        );
2189        // 3 < -303
2190        assert_eq!(
2191            eval.interpret_inline_policy(&Expr::less(Expr::val(3), Expr::val(-303))),
2192            Ok(Value::Lit(Literal::Bool(false)))
2193        );
2194        // -303 < -1
2195        assert_eq!(
2196            eval.interpret_inline_policy(&Expr::less(Expr::val(-303), Expr::val(-1))),
2197            Ok(Value::Lit(Literal::Bool(true)))
2198        );
2199        // 3 < 3
2200        assert_eq!(
2201            eval.interpret_inline_policy(&Expr::less(Expr::val(3), Expr::val(3))),
2202            Ok(Value::Lit(Literal::Bool(false)))
2203        );
2204        // -33 <= 0
2205        assert_eq!(
2206            eval.interpret_inline_policy(&Expr::lesseq(Expr::val(-33), Expr::val(0))),
2207            Ok(Value::Lit(Literal::Bool(true)))
2208        );
2209        // 3 <= 3
2210        assert_eq!(
2211            eval.interpret_inline_policy(&Expr::lesseq(Expr::val(3), Expr::val(3))),
2212            Ok(Value::Lit(Literal::Bool(true)))
2213        );
2214        // 7 > 3
2215        assert_eq!(
2216            eval.interpret_inline_policy(&Expr::greater(Expr::val(7), Expr::val(3))),
2217            Ok(Value::Lit(Literal::Bool(true)))
2218        );
2219        // 7 > -3
2220        assert_eq!(
2221            eval.interpret_inline_policy(&Expr::greater(Expr::val(7), Expr::val(-3))),
2222            Ok(Value::Lit(Literal::Bool(true)))
2223        );
2224        // 7 > 7
2225        assert_eq!(
2226            eval.interpret_inline_policy(&Expr::greater(Expr::val(7), Expr::val(7))),
2227            Ok(Value::Lit(Literal::Bool(false)))
2228        );
2229        // 0 >= -7
2230        assert_eq!(
2231            eval.interpret_inline_policy(&Expr::greatereq(Expr::val(0), Expr::val(-7))),
2232            Ok(Value::Lit(Literal::Bool(true)))
2233        );
2234        // -1 >= 7
2235        assert_eq!(
2236            eval.interpret_inline_policy(&Expr::greatereq(Expr::val(-1), Expr::val(7))),
2237            Ok(Value::Lit(Literal::Bool(false)))
2238        );
2239        // 7 >= 7
2240        assert_eq!(
2241            eval.interpret_inline_policy(&Expr::greatereq(Expr::val(7), Expr::val(7))),
2242            Ok(Value::Lit(Literal::Bool(true)))
2243        );
2244        // false < true
2245        assert_eq!(
2246            eval.interpret_inline_policy(&Expr::less(Expr::val(false), Expr::val(true))),
2247            Err(EvaluationError::TypeError {
2248                expected: vec![Type::Long],
2249                actual: Type::Bool
2250            })
2251        );
2252        // false < false
2253        assert_eq!(
2254            eval.interpret_inline_policy(&Expr::less(Expr::val(false), Expr::val(false))),
2255            Err(EvaluationError::TypeError {
2256                expected: vec![Type::Long],
2257                actual: Type::Bool
2258            })
2259        );
2260        // true <= false
2261        assert_eq!(
2262            eval.interpret_inline_policy(&Expr::lesseq(Expr::val(true), Expr::val(false))),
2263            Err(EvaluationError::TypeError {
2264                expected: vec![Type::Long],
2265                actual: Type::Bool
2266            })
2267        );
2268        // false <= false
2269        assert_eq!(
2270            eval.interpret_inline_policy(&Expr::lesseq(Expr::val(false), Expr::val(false))),
2271            Err(EvaluationError::TypeError {
2272                expected: vec![Type::Long],
2273                actual: Type::Bool
2274            })
2275        );
2276        // false > true
2277        assert_eq!(
2278            eval.interpret_inline_policy(&Expr::greater(Expr::val(false), Expr::val(true))),
2279            Err(EvaluationError::TypeError {
2280                expected: vec![Type::Long],
2281                actual: Type::Bool
2282            })
2283        );
2284        // true > true
2285        assert_eq!(
2286            eval.interpret_inline_policy(&Expr::greater(Expr::val(true), Expr::val(true))),
2287            Err(EvaluationError::TypeError {
2288                expected: vec![Type::Long],
2289                actual: Type::Bool
2290            })
2291        );
2292        // true >= false
2293        assert_eq!(
2294            eval.interpret_inline_policy(&Expr::greatereq(Expr::val(true), Expr::val(false))),
2295            Err(EvaluationError::TypeError {
2296                expected: vec![Type::Long],
2297                actual: Type::Bool
2298            })
2299        );
2300        // true >= true
2301        assert_eq!(
2302            eval.interpret_inline_policy(&Expr::greatereq(Expr::val(true), Expr::val(true))),
2303            Err(EvaluationError::TypeError {
2304                expected: vec![Type::Long],
2305                actual: Type::Bool
2306            })
2307        );
2308        // bc < zzz
2309        assert_eq!(
2310            eval.interpret_inline_policy(&Expr::less(Expr::val("bc"), Expr::val("zzz"))),
2311            Err(EvaluationError::TypeError {
2312                expected: vec![Type::Long],
2313                actual: Type::String
2314            })
2315        );
2316        // banana < zzz
2317        assert_eq!(
2318            eval.interpret_inline_policy(&Expr::less(Expr::val("banana"), Expr::val("zzz"))),
2319            Err(EvaluationError::TypeError {
2320                expected: vec![Type::Long],
2321                actual: Type::String
2322            })
2323        );
2324        // "" < zzz
2325        assert_eq!(
2326            eval.interpret_inline_policy(&Expr::less(Expr::val(""), Expr::val("zzz"))),
2327            Err(EvaluationError::TypeError {
2328                expected: vec![Type::Long],
2329                actual: Type::String
2330            })
2331        );
2332        // a < 1
2333        assert_eq!(
2334            eval.interpret_inline_policy(&Expr::less(Expr::val("a"), Expr::val("1"))),
2335            Err(EvaluationError::TypeError {
2336                expected: vec![Type::Long],
2337                actual: Type::String
2338            })
2339        );
2340        // a < A
2341        assert_eq!(
2342            eval.interpret_inline_policy(&Expr::less(Expr::val("a"), Expr::val("A"))),
2343            Err(EvaluationError::TypeError {
2344                expected: vec![Type::Long],
2345                actual: Type::String
2346            })
2347        );
2348        // A < A
2349        assert_eq!(
2350            eval.interpret_inline_policy(&Expr::less(Expr::val("A"), Expr::val("A"))),
2351            Err(EvaluationError::TypeError {
2352                expected: vec![Type::Long],
2353                actual: Type::String
2354            })
2355        );
2356        // zebra < zebras
2357        assert_eq!(
2358            eval.interpret_inline_policy(&Expr::less(Expr::val("zebra"), Expr::val("zebras"))),
2359            Err(EvaluationError::TypeError {
2360                expected: vec![Type::Long],
2361                actual: Type::String
2362            })
2363        );
2364        // zebra <= zebras
2365        assert_eq!(
2366            eval.interpret_inline_policy(&Expr::lesseq(Expr::val("zebra"), Expr::val("zebras"))),
2367            Err(EvaluationError::TypeError {
2368                expected: vec![Type::Long],
2369                actual: Type::String
2370            })
2371        );
2372        // zebras <= zebras
2373        assert_eq!(
2374            eval.interpret_inline_policy(&Expr::lesseq(Expr::val("zebras"), Expr::val("zebras"))),
2375            Err(EvaluationError::TypeError {
2376                expected: vec![Type::Long],
2377                actual: Type::String
2378            })
2379        );
2380        // zebras <= Zebras
2381        assert_eq!(
2382            eval.interpret_inline_policy(&Expr::lesseq(Expr::val("zebras"), Expr::val("Zebras"))),
2383            Err(EvaluationError::TypeError {
2384                expected: vec![Type::Long],
2385                actual: Type::String
2386            })
2387        );
2388        // 123 > 78
2389        assert_eq!(
2390            eval.interpret_inline_policy(&Expr::greater(Expr::val("123"), Expr::val("78"))),
2391            Err(EvaluationError::TypeError {
2392                expected: vec![Type::Long],
2393                actual: Type::String
2394            })
2395        );
2396        // <space>zebras >= zebras
2397        assert_eq!(
2398            eval.interpret_inline_policy(&Expr::greatereq(
2399                Expr::val(" zebras"),
2400                Expr::val("zebras")
2401            )),
2402            Err(EvaluationError::TypeError {
2403                expected: vec![Type::Long],
2404                actual: Type::String
2405            })
2406        );
2407        // "" >= ""
2408        assert_eq!(
2409            eval.interpret_inline_policy(&Expr::greatereq(Expr::val(""), Expr::val(""))),
2410            Err(EvaluationError::TypeError {
2411                expected: vec![Type::Long],
2412                actual: Type::String
2413            })
2414        );
2415        // "" >= _hi
2416        assert_eq!(
2417            eval.interpret_inline_policy(&Expr::greatereq(Expr::val(""), Expr::val("_hi"))),
2418            Err(EvaluationError::TypeError {
2419                expected: vec![Type::Long],
2420                actual: Type::String
2421            })
2422        );
2423        // 🦀 >= _hi
2424        assert_eq!(
2425            eval.interpret_inline_policy(&Expr::greatereq(Expr::val("🦀"), Expr::val("_hi"))),
2426            Err(EvaluationError::TypeError {
2427                expected: vec![Type::Long],
2428                actual: Type::String
2429            })
2430        );
2431        // 2 < "4"
2432        assert_eq!(
2433            eval.interpret_inline_policy(&Expr::less(Expr::val(2), Expr::val("4"))),
2434            Err(EvaluationError::TypeError {
2435                expected: vec![Type::Long],
2436                actual: Type::String
2437            })
2438        );
2439        // "4" < 2
2440        assert_eq!(
2441            eval.interpret_inline_policy(&Expr::less(Expr::val("4"), Expr::val(2))),
2442            Err(EvaluationError::TypeError {
2443                expected: vec![Type::Long],
2444                actual: Type::String
2445            })
2446        );
2447        // false < 1
2448        assert_eq!(
2449            eval.interpret_inline_policy(&Expr::less(Expr::val(false), Expr::val(1))),
2450            Err(EvaluationError::TypeError {
2451                expected: vec![Type::Long],
2452                actual: Type::Bool
2453            })
2454        );
2455        // 1 < false
2456        assert_eq!(
2457            eval.interpret_inline_policy(&Expr::less(Expr::val(1), Expr::val(false))),
2458            Err(EvaluationError::TypeError {
2459                expected: vec![Type::Long],
2460                actual: Type::Bool
2461            })
2462        );
2463        // [1, 2] < [47, 0]
2464        assert_eq!(
2465            eval.interpret_inline_policy(&Expr::less(
2466                Expr::set(vec![Expr::val(1), Expr::val(2)]),
2467                Expr::set(vec![Expr::val(47), Expr::val(0)])
2468            )),
2469            Err(EvaluationError::TypeError {
2470                expected: vec![Type::Long],
2471                actual: Type::Set
2472            })
2473        );
2474    }
2475
2476    #[test]
2477    fn interpret_arithmetic() {
2478        let request = basic_request();
2479        let entities = basic_entities();
2480        let exts = Extensions::none();
2481        let eval = Evaluator::new(&request, &entities, &exts).expect("failed to create evaluator");
2482        // 11 + 22
2483        assert_eq!(
2484            eval.interpret_inline_policy(&Expr::add(Expr::val(11), Expr::val(22))),
2485            Ok(Value::Lit(Literal::Long(33)))
2486        );
2487        // 11 + 0
2488        assert_eq!(
2489            eval.interpret_inline_policy(&Expr::add(Expr::val(11), Expr::val(0))),
2490            Ok(Value::Lit(Literal::Long(11)))
2491        );
2492        // -1 + 1
2493        assert_eq!(
2494            eval.interpret_inline_policy(&Expr::add(Expr::val(-1), Expr::val(1))),
2495            Ok(Value::Lit(Literal::Long(0)))
2496        );
2497        // overflow
2498        assert_eq!(
2499            eval.interpret_inline_policy(&Expr::add(Expr::val(std::i64::MAX), Expr::val(1))),
2500            Err(EvaluationError::IntegerOverflow(
2501                IntegerOverflowError::BinaryOp {
2502                    op: BinaryOp::Add,
2503                    arg1: Value::from(std::i64::MAX),
2504                    arg2: Value::from(1),
2505                }
2506            ))
2507        );
2508        // 7 + "3"
2509        assert_eq!(
2510            eval.interpret_inline_policy(&Expr::add(Expr::val(7), Expr::val("3"))),
2511            Err(EvaluationError::TypeError {
2512                expected: vec![Type::Long],
2513                actual: Type::String
2514            })
2515        );
2516        // 44 - 31
2517        assert_eq!(
2518            eval.interpret_inline_policy(&Expr::sub(Expr::val(44), Expr::val(31))),
2519            Ok(Value::Lit(Literal::Long(13)))
2520        );
2521        // 5 - (-3)
2522        assert_eq!(
2523            eval.interpret_inline_policy(&Expr::sub(Expr::val(5), Expr::val(-3))),
2524            Ok(Value::Lit(Literal::Long(8)))
2525        );
2526        // overflow
2527        assert_eq!(
2528            eval.interpret_inline_policy(&Expr::sub(Expr::val(std::i64::MIN + 2), Expr::val(3))),
2529            Err(EvaluationError::IntegerOverflow(
2530                IntegerOverflowError::BinaryOp {
2531                    op: BinaryOp::Sub,
2532                    arg1: Value::from(std::i64::MIN + 2),
2533                    arg2: Value::from(3),
2534                }
2535            ))
2536        );
2537        // "ham" - "ha"
2538        assert_eq!(
2539            eval.interpret_inline_policy(&Expr::sub(Expr::val("ham"), Expr::val("ha"))),
2540            Err(EvaluationError::TypeError {
2541                expected: vec![Type::Long],
2542                actual: Type::String
2543            })
2544        );
2545        // 5 * (-3)
2546        assert_eq!(
2547            eval.interpret_inline_policy(&Expr::mul(Expr::val(5), -3)),
2548            Ok(Value::Lit(Literal::Long(-15)))
2549        );
2550        // 5 * 0
2551        assert_eq!(
2552            eval.interpret_inline_policy(&Expr::mul(Expr::val(5), 0)),
2553            Ok(Value::Lit(Literal::Long(0)))
2554        );
2555        // "5" * 0
2556        assert_eq!(
2557            eval.interpret_inline_policy(&Expr::mul(Expr::val("5"), 0)),
2558            Err(EvaluationError::TypeError {
2559                expected: vec![Type::Long],
2560                actual: Type::String
2561            })
2562        );
2563        // overflow
2564        assert_eq!(
2565            eval.interpret_inline_policy(&Expr::mul(Expr::val(std::i64::MAX - 1), 3)),
2566            Err(EvaluationError::IntegerOverflow(
2567                IntegerOverflowError::Multiplication {
2568                    arg: Value::from(std::i64::MAX - 1),
2569                    constant: 3,
2570                }
2571            ))
2572        );
2573    }
2574
2575    #[test]
2576    fn interpret_set_and_map_membership() {
2577        let request = basic_request();
2578        let entities = rich_entities();
2579        let exts = Extensions::none();
2580        let eval = Evaluator::new(&request, &entities, &exts).expect("failed to create evaluator");
2581
2582        // [2, 3, 4] contains 2
2583        assert_eq!(
2584            eval.interpret_inline_policy(&Expr::contains(
2585                Expr::set(vec![Expr::val(2), Expr::val(3), Expr::val(4)]),
2586                Expr::val(2)
2587            )),
2588            Ok(Value::Lit(Literal::Bool(true)))
2589        );
2590        // [34, 2, -7] contains 2
2591        assert_eq!(
2592            eval.interpret_inline_policy(&Expr::contains(
2593                Expr::set(vec![Expr::val(34), Expr::val(2), Expr::val(-7)]),
2594                Expr::val(2)
2595            )),
2596            Ok(Value::Lit(Literal::Bool(true)))
2597        );
2598        // [34, 2, -7] contains 3
2599        assert_eq!(
2600            eval.interpret_inline_policy(&Expr::contains(
2601                Expr::set(vec![Expr::val(34), Expr::val(2), Expr::val(-7)]),
2602                Expr::val(3)
2603            )),
2604            Ok(Value::Lit(Literal::Bool(false)))
2605        );
2606        // [] contains 7
2607        assert_eq!(
2608            eval.interpret_inline_policy(&Expr::contains(Expr::set(vec![]), Expr::val(7))),
2609            Ok(Value::Lit(Literal::Bool(false)))
2610        );
2611        // ["some", "useful", "tags"] contains "foo"
2612        assert_eq!(
2613            eval.interpret_inline_policy(&Expr::contains(
2614                Expr::set(vec![
2615                    Expr::val("some"),
2616                    Expr::val("useful"),
2617                    Expr::val("tags")
2618                ]),
2619                Expr::val("foo")
2620            )),
2621            Ok(Value::Lit(Literal::Bool(false)))
2622        );
2623        // ["some", "useful", "tags"] contains "useful"
2624        assert_eq!(
2625            eval.interpret_inline_policy(&Expr::contains(
2626                Expr::set(vec![
2627                    Expr::val("some"),
2628                    Expr::val("useful"),
2629                    Expr::val("tags")
2630                ]),
2631                Expr::val("useful")
2632            )),
2633            Ok(Value::Lit(Literal::Bool(true)))
2634        );
2635        // [<entity child>, <entity sibling>] contains <entity child>
2636        assert_eq!(
2637            eval.interpret_inline_policy(&Expr::contains(
2638                Expr::set(vec![
2639                    Expr::val(EntityUID::with_eid("child")),
2640                    Expr::val(EntityUID::with_eid("sibling"))
2641                ]),
2642                Expr::val(EntityUID::with_eid("child"))
2643            )),
2644            Ok(Value::Lit(Literal::Bool(true)))
2645        );
2646        // [<entity parent>, <entity sibling>] contains <entity child>
2647        assert_eq!(
2648            eval.interpret_inline_policy(&Expr::contains(
2649                Expr::set(vec![
2650                    Expr::val(EntityUID::with_eid("parent")),
2651                    Expr::val(EntityUID::with_eid("sibling"))
2652                ]),
2653                Expr::val(EntityUID::with_eid("child"))
2654            )),
2655            Ok(Value::Lit(Literal::Bool(false)))
2656        );
2657        // ["foo", "bar"] contains 3
2658        assert_eq!(
2659            eval.interpret_inline_policy(&Expr::contains(
2660                Expr::set(vec![Expr::val("foo"), Expr::val("bar")]),
2661                Expr::val(3)
2662            )),
2663            Ok(Value::Lit(Literal::Bool(false)))
2664        );
2665        // ["foo", "bar"] contains [3]
2666        assert_eq!(
2667            eval.interpret_inline_policy(&Expr::contains(
2668                Expr::set(vec![Expr::val("foo"), Expr::val("bar")]),
2669                Expr::set(vec![Expr::val(3)])
2670            )),
2671            Ok(Value::Lit(Literal::Bool(false)))
2672        );
2673        // [[7], "eggs", [3]] contains [3]
2674        assert_eq!(
2675            eval.interpret_inline_policy(&Expr::contains(
2676                Expr::set(vec![
2677                    Expr::set(vec![Expr::val(7)]),
2678                    Expr::val("eggs"),
2679                    Expr::set(vec![Expr::val(3)])
2680                ]),
2681                Expr::set(vec![Expr::val(3)])
2682            )),
2683            Ok(Value::Lit(Literal::Bool(true)))
2684        );
2685
2686        // ["2", 20, true, <entity foo>] contains 2
2687        assert_eq!(
2688            eval.interpret_inline_policy(&Expr::contains(
2689                Expr::set(vec![
2690                    Expr::val("2"),
2691                    Expr::val(20),
2692                    Expr::val(true),
2693                    Expr::val(EntityUID::with_eid("foo")),
2694                ]),
2695                Expr::val(2)
2696            )),
2697            Ok(Value::Lit(Literal::Bool(false)))
2698        );
2699        // ["ham", entity_with_attrs.address.town, -1] contains "barmstadt"
2700        assert_eq!(
2701            eval.interpret_inline_policy(&Expr::contains(
2702                Expr::set(vec![
2703                    Expr::val("ham"),
2704                    Expr::get_attr(
2705                        Expr::get_attr(
2706                            Expr::val(EntityUID::with_eid("entity_with_attrs")),
2707                            "address".into()
2708                        ),
2709                        "town".into()
2710                    ),
2711                    Expr::val(-1),
2712                ]),
2713                Expr::val("barmstadt")
2714            )),
2715            Ok(Value::Lit(Literal::Bool(true)))
2716        );
2717        // 3 contains 7
2718        assert_eq!(
2719            eval.interpret_inline_policy(&Expr::contains(Expr::val(3), Expr::val(7))),
2720            Err(EvaluationError::TypeError {
2721                expected: vec![Type::Set],
2722                actual: Type::Long
2723            })
2724        );
2725        // { ham: "eggs" } contains "ham"
2726        assert_eq!(
2727            eval.interpret_inline_policy(&Expr::contains(
2728                Expr::record(vec![("ham".into(), Expr::val("eggs"))]),
2729                Expr::val("ham")
2730            )),
2731            Err(EvaluationError::TypeError {
2732                expected: vec![Type::Set],
2733                actual: Type::Record,
2734            })
2735        );
2736        // wrong argument order
2737        assert_eq!(
2738            eval.interpret_inline_policy(&Expr::contains(
2739                Expr::val(3),
2740                Expr::set(vec![Expr::val(1), Expr::val(3), Expr::val(7)])
2741            )),
2742            Err(EvaluationError::TypeError {
2743                expected: vec![Type::Set],
2744                actual: Type::Long,
2745            })
2746        );
2747    }
2748
2749    #[test]
2750    fn interpret_hierarchy_membership() {
2751        let request = basic_request();
2752        let entities = rich_entities();
2753        let exts = Extensions::none();
2754        let eval = Evaluator::new(&request, &entities, &exts).expect("failed to create evaluator");
2755        // A in B, where A and B are unrelated (but same type)
2756        assert_eq!(
2757            eval.interpret_inline_policy(&Expr::is_in(
2758                Expr::val(EntityUID::with_eid("child")),
2759                Expr::val(EntityUID::with_eid("unrelated"))
2760            )),
2761            Ok(Value::Lit(Literal::Bool(false)))
2762        );
2763        // A in B, where A and B are the same type and it's true
2764        assert_eq!(
2765            eval.interpret_inline_policy(&Expr::is_in(
2766                Expr::val(EntityUID::with_eid("child")),
2767                Expr::val(EntityUID::with_eid("parent"))
2768            )),
2769            Ok(Value::Lit(Literal::Bool(true)))
2770        );
2771        // A in B, where A and B are different types and it's true
2772        assert_eq!(
2773            eval.interpret_inline_policy(&Expr::is_in(
2774                Expr::val(
2775                    EntityUID::with_eid_and_type("other_type", "other_child")
2776                        .expect("should be a valid identifier")
2777                ),
2778                Expr::val(EntityUID::with_eid("parent"))
2779            )),
2780            Ok(Value::Lit(Literal::Bool(true)))
2781        );
2782        // A in B, where A and B are unrelated _and_ different types
2783        assert_eq!(
2784            eval.interpret_inline_policy(&Expr::is_in(
2785                Expr::val(
2786                    EntityUID::with_eid_and_type("other_type", "other_child")
2787                        .expect("should be a valid identifier")
2788                ),
2789                Expr::val(EntityUID::with_eid("unrelated"))
2790            )),
2791            Ok(Value::Lit(Literal::Bool(false)))
2792        );
2793        // A in B, where A and B are siblings
2794        assert_eq!(
2795            eval.interpret_inline_policy(&Expr::is_in(
2796                Expr::val(EntityUID::with_eid("child")),
2797                Expr::val(EntityUID::with_eid("sibling"))
2798            )),
2799            Ok(Value::Lit(Literal::Bool(false)))
2800        );
2801        // A in A, where A exists
2802        assert_eq!(
2803            eval.interpret_inline_policy(&Expr::is_in(
2804                Expr::val(EntityUID::with_eid("parent")),
2805                Expr::val(EntityUID::with_eid("parent"))
2806            )),
2807            Ok(Value::Lit(Literal::Bool(true)))
2808        );
2809        // A in A, where A does not exist
2810        assert_eq!(
2811            eval.interpret_inline_policy(&Expr::is_in(
2812                Expr::val(EntityUID::with_eid("doesnotexist")),
2813                Expr::val(EntityUID::with_eid("doesnotexist")),
2814            )),
2815            Ok(Value::Lit(Literal::Bool(true)))
2816        );
2817        // A in A, where A is unspecified
2818        assert_eq!(
2819            eval.interpret_inline_policy(&Expr::is_in(
2820                Expr::val(EntityUID::unspecified_from_eid(Eid::new("foo"))),
2821                Expr::val(EntityUID::unspecified_from_eid(Eid::new("foo"))),
2822            )),
2823            Ok(Value::Lit(Literal::Bool(true)))
2824        );
2825        // A in B, where actually B in A
2826        assert_eq!(
2827            eval.interpret_inline_policy(&Expr::is_in(
2828                Expr::val(EntityUID::with_eid("parent")),
2829                Expr::val(EntityUID::with_eid("child"))
2830            )),
2831            Ok(Value::Lit(Literal::Bool(false)))
2832        );
2833        // A in B, where actually A is a grandchild of B
2834        assert_eq!(
2835            eval.interpret_inline_policy(&Expr::is_in(
2836                Expr::val(EntityUID::with_eid("child")),
2837                Expr::val(EntityUID::with_eid("grandparent"))
2838            )),
2839            Ok(Value::Lit(Literal::Bool(true)))
2840        );
2841        // A in B, where A doesn't exist but B does
2842        assert_eq!(
2843            eval.interpret_inline_policy(&Expr::is_in(
2844                Expr::val(EntityUID::with_eid("doesnotexist")),
2845                Expr::val(EntityUID::with_eid("parent"))
2846            )),
2847            Ok(Value::Lit(Literal::Bool(false)))
2848        );
2849        // A in B, where B doesn't exist but A does
2850        assert_eq!(
2851            eval.interpret_inline_policy(&Expr::is_in(
2852                Expr::val(EntityUID::with_eid("parent")),
2853                Expr::val(EntityUID::with_eid("doesnotexist"))
2854            )),
2855            Ok(Value::Lit(Literal::Bool(false)))
2856        );
2857        // A in B, where A is unspecified but B exists
2858        assert_eq!(
2859            eval.interpret_inline_policy(&Expr::is_in(
2860                Expr::val(EntityUID::unspecified_from_eid(Eid::new("foo"))),
2861                Expr::val(EntityUID::with_eid("parent"))
2862            )),
2863            Ok(Value::Lit(Literal::Bool(false)))
2864        );
2865        // A in B, where A exists but B is unspecified
2866        assert_eq!(
2867            eval.interpret_inline_policy(&Expr::is_in(
2868                Expr::val(EntityUID::with_eid("parent")),
2869                Expr::val(EntityUID::unspecified_from_eid(Eid::new("foo")))
2870            )),
2871            Ok(Value::Lit(Literal::Bool(false)))
2872        );
2873        // A in [B, C] where A in B but not A in C
2874        assert_eq!(
2875            eval.interpret_inline_policy(&Expr::is_in(
2876                Expr::val(EntityUID::with_eid("child")),
2877                Expr::set(vec![
2878                    Expr::val(EntityUID::with_eid("grandparent")),
2879                    Expr::val(EntityUID::with_eid("sibling")),
2880                ])
2881            )),
2882            Ok(Value::Lit(Literal::Bool(true)))
2883        );
2884        // A in [B, C] where A in C but not A in B
2885        assert_eq!(
2886            eval.interpret_inline_policy(&Expr::is_in(
2887                Expr::val(EntityUID::with_eid("child")),
2888                Expr::set(vec![
2889                    Expr::val(EntityUID::with_eid("sibling")),
2890                    Expr::val(EntityUID::with_eid("grandparent")),
2891                ])
2892            )),
2893            Ok(Value::Lit(Literal::Bool(true)))
2894        );
2895        // A in [B, C] where A is in neither B nor C
2896        assert_eq!(
2897            eval.interpret_inline_policy(&Expr::is_in(
2898                Expr::val(EntityUID::with_eid("child")),
2899                Expr::set(vec![
2900                    Expr::val(EntityUID::with_eid("sibling")),
2901                    Expr::val(EntityUID::with_eid("unrelated")),
2902                ])
2903            )),
2904            Ok(Value::Lit(Literal::Bool(false)))
2905        );
2906        // A in [A, B] where B is unrelated
2907        assert_eq!(
2908            eval.interpret_inline_policy(&Expr::is_in(
2909                Expr::val(EntityUID::with_eid("child")),
2910                Expr::set(vec![
2911                    Expr::val(EntityUID::with_eid("unrelated")),
2912                    Expr::val(EntityUID::with_eid("child")),
2913                ])
2914            )),
2915            Ok(Value::Lit(Literal::Bool(true)))
2916        );
2917        // A in [B, A] where B is unrelated
2918        assert_eq!(
2919            eval.interpret_inline_policy(&Expr::is_in(
2920                Expr::val(EntityUID::with_eid("child")),
2921                Expr::set(vec![
2922                    Expr::val(EntityUID::with_eid("child")),
2923                    Expr::val(EntityUID::with_eid("unrelated")),
2924                ])
2925            )),
2926            Ok(Value::Lit(Literal::Bool(true)))
2927        );
2928        // A in [A, true]
2929        assert_eq!(
2930            eval.interpret_inline_policy(&Expr::is_in(
2931                Expr::val(EntityUID::with_eid("child")),
2932                Expr::set(vec![
2933                    Expr::val(EntityUID::with_eid("child")),
2934                    Expr::val(true),
2935                ])
2936            )),
2937            Err(EvaluationError::TypeError {
2938                expected: vec![Type::entity_type(
2939                    Name::parse_unqualified_name("any_entity_type")
2940                        .expect("should be a valid identifier")
2941                )],
2942                actual: Type::Bool,
2943            })
2944        );
2945        // A in [A, B] where A and B do not exist
2946        assert_eq!(
2947            eval.interpret_inline_policy(&Expr::is_in(
2948                Expr::val(EntityUID::with_eid("doesnotexistA")),
2949                Expr::set(vec![
2950                    Expr::val(EntityUID::with_eid("doesnotexistA")),
2951                    Expr::val(EntityUID::with_eid("doesnotexistB")),
2952                ])
2953            )),
2954            Ok(Value::Lit(Literal::Bool(true)))
2955        );
2956        // A in [B, C] where none of A, B, or C exist
2957        assert_eq!(
2958            eval.interpret_inline_policy(&Expr::is_in(
2959                Expr::val(EntityUID::with_eid("doesnotexistA")),
2960                Expr::set(vec![
2961                    Expr::val(EntityUID::with_eid("doesnotexistB")),
2962                    Expr::val(EntityUID::with_eid("doesnotexistC")),
2963                ])
2964            )),
2965            Ok(Value::Lit(Literal::Bool(false)))
2966        );
2967        // A in [B, C] where B and C do not exist but A does
2968        assert_eq!(
2969            eval.interpret_inline_policy(&Expr::is_in(
2970                Expr::val(EntityUID::with_eid("child")),
2971                Expr::set(vec![
2972                    Expr::val(EntityUID::with_eid("doesnotexistB")),
2973                    Expr::val(EntityUID::with_eid("doesnotexistC")),
2974                ])
2975            )),
2976            Ok(Value::Lit(Literal::Bool(false)))
2977        );
2978        // A in [B, C] where B and C exist but A does not
2979        assert_eq!(
2980            eval.interpret_inline_policy(&Expr::is_in(
2981                Expr::val(EntityUID::with_eid("doesnotexistA")),
2982                Expr::set(vec![
2983                    Expr::val(EntityUID::with_eid("child")),
2984                    Expr::val(EntityUID::with_eid("grandparent")),
2985                ])
2986            )),
2987            Ok(Value::Lit(Literal::Bool(false)))
2988        );
2989        // "foo" in "foobar"
2990        assert_eq!(
2991            eval.interpret_inline_policy(&Expr::is_in(Expr::val("foo"), Expr::val("foobar"))),
2992            Err(EvaluationError::TypeError {
2993                expected: vec![Type::entity_type(
2994                    Name::parse_unqualified_name("any_entity_type")
2995                        .expect("should be a valid identifier")
2996                )],
2997                actual: Type::String
2998            })
2999        );
3000        // "spoon" in A (where has(A.spoon))
3001        assert_eq!(
3002            eval.interpret_inline_policy(&Expr::is_in(
3003                Expr::val("spoon"),
3004                Expr::val(EntityUID::with_eid("entity_with_attrs"))
3005            )),
3006            Err(EvaluationError::TypeError {
3007                expected: vec![Type::entity_type(
3008                    Name::parse_unqualified_name("any_entity_type")
3009                        .expect("should be a valid identifier")
3010                )],
3011                actual: Type::String
3012            })
3013        );
3014        // 3 in [34, -2, 7]
3015        assert_eq!(
3016            eval.interpret_inline_policy(&Expr::is_in(
3017                Expr::val(3),
3018                Expr::set(vec![Expr::val(34), Expr::val(-2), Expr::val(7)])
3019            )),
3020            Err(EvaluationError::TypeError {
3021                expected: vec![Type::entity_type(
3022                    Name::parse_unqualified_name("any_entity_type")
3023                        .expect("should be a valid identifier")
3024                )],
3025                actual: Type::Long
3026            })
3027        );
3028        // "foo" in { "foo": 2, "bar": true }
3029        assert_eq!(
3030            eval.interpret_inline_policy(&Expr::is_in(
3031                Expr::val("foo"),
3032                Expr::record(vec![
3033                    ("foo".into(), Expr::val(2)),
3034                    ("bar".into(), Expr::val(true)),
3035                ])
3036            )),
3037            Err(EvaluationError::TypeError {
3038                expected: vec![Type::entity_type(
3039                    Name::parse_unqualified_name("any_entity_type")
3040                        .expect("should be a valid identifier")
3041                )],
3042                actual: Type::String
3043            })
3044        );
3045        // A in { "foo": 2, "bar": true }
3046        assert_eq!(
3047            eval.interpret_inline_policy(&Expr::is_in(
3048                Expr::val(EntityUID::with_eid("child")),
3049                Expr::record(vec![
3050                    ("foo".into(), Expr::val(2)),
3051                    ("bar".into(), Expr::val(true)),
3052                ])
3053            )),
3054            Err(EvaluationError::TypeError {
3055                expected: vec![
3056                    Type::Set,
3057                    Type::entity_type(
3058                        Name::parse_unqualified_name("any_entity_type")
3059                            .expect("should be a valid identifier")
3060                    )
3061                ],
3062                actual: Type::Record
3063            })
3064        );
3065    }
3066
3067    #[test]
3068    fn interpret_hierarchy_membership_slice() {
3069        // User::"Alice" in Group::"Friends".
3070        // Slice.attributes = {Alice},
3071        // Slice.hierarchy = {Alice, Group::Friends}
3072        // Should be allow under new semantics for "in"
3073
3074        let request = Request::new(
3075            EntityUID::with_eid("Alice"),
3076            EntityUID::with_eid("test_action"),
3077            EntityUID::with_eid("test_resource"),
3078            Context::empty(),
3079        );
3080        //Alice has parent "Friends" but we don't add "Friends" to the slice
3081        let mut alice = Entity::with_uid(EntityUID::with_eid("Alice"));
3082        let parent = Entity::with_uid(EntityUID::with_eid("Friends"));
3083        alice.add_ancestor(parent.uid());
3084        let entities = Entities::from_entities(vec![alice], TCComputation::AssumeAlreadyComputed)
3085            .expect("failed to create basic entities");
3086        let exts = Extensions::none();
3087        let eval = Evaluator::new(&request, &entities, &exts).expect("failed to create evaluator");
3088        assert_eq!(
3089            eval.interpret_inline_policy(&Expr::is_in(
3090                Expr::val(EntityUID::with_eid("Alice")),
3091                Expr::val(EntityUID::with_eid("Friends"))
3092            )),
3093            Ok(Value::Lit(Literal::Bool(true)))
3094        );
3095        assert_eq!(
3096            eval.interpret_inline_policy(&Expr::is_in(
3097                Expr::val(EntityUID::with_eid("Bob")),
3098                Expr::val(EntityUID::with_eid("Friends"))
3099            )),
3100            Ok(Value::Lit(Literal::Bool(false)))
3101        );
3102        assert_eq!(
3103            eval.interpret_inline_policy(&Expr::is_in(
3104                Expr::val(EntityUID::with_eid("Alice")),
3105                Expr::set(vec![
3106                    Expr::val(EntityUID::with_eid("Friends")),
3107                    Expr::val(EntityUID::with_eid("Bob"))
3108                ])
3109            )),
3110            Ok(Value::Lit(Literal::Bool(true)))
3111        );
3112        assert_eq!(
3113            eval.interpret_inline_policy(&Expr::is_in(
3114                Expr::val(EntityUID::with_eid("Bob")),
3115                Expr::set(vec![
3116                    Expr::val(EntityUID::with_eid("Friends")),
3117                    Expr::val(EntityUID::with_eid("Alice"))
3118                ])
3119            )),
3120            Ok(Value::Lit(Literal::Bool(false)))
3121        );
3122    }
3123
3124    #[test]
3125    fn interpret_string_like() {
3126        let request = basic_request();
3127        let entities = basic_entities();
3128        let exts = Extensions::none();
3129        let eval = Evaluator::new(&request, &entities, &exts).expect("failed to create evaluator");
3130        // "eggs" vs "ham"
3131        assert_eq!(
3132            eval.interpret_inline_policy(
3133                &parse_expr(r#""eggs" like "ham*""#).expect("parsing error")
3134            ),
3135            Ok(Value::Lit(Literal::Bool(false)))
3136        );
3137        assert_eq!(
3138            eval.interpret_inline_policy(
3139                &parse_expr(r#""eggs" like "*ham""#).expect("parsing error")
3140            ),
3141            Ok(Value::Lit(Literal::Bool(false)))
3142        );
3143        assert_eq!(
3144            eval.interpret_inline_policy(
3145                &parse_expr(r#""eggs" like "*ham*""#).expect("parsing error")
3146            ),
3147            Ok(Value::Lit(Literal::Bool(false)))
3148        );
3149        // "ham and eggs" vs "ham"
3150        assert_eq!(
3151            eval.interpret_inline_policy(
3152                &parse_expr(r#""ham and eggs" like "ham*""#).expect("parsing error")
3153            ),
3154            Ok(Value::Lit(Literal::Bool(true)))
3155        );
3156        assert_eq!(
3157            eval.interpret_inline_policy(
3158                &parse_expr(r#""ham and eggs" like "*ham""#).expect("parsing error")
3159            ),
3160            Ok(Value::Lit(Literal::Bool(false)))
3161        );
3162        assert_eq!(
3163            eval.interpret_inline_policy(
3164                &parse_expr(r#""ham and eggs" like "*ham*""#).expect("parsing error")
3165            ),
3166            Ok(Value::Lit(Literal::Bool(true)))
3167        );
3168        assert_eq!(
3169            eval.interpret_inline_policy(
3170                &parse_expr(r#""ham and eggs" like "*h*a*m*""#).expect("parsing error")
3171            ),
3172            Ok(Value::Lit(Literal::Bool(true)))
3173        );
3174        // "eggs and ham" vs "ham"
3175        assert_eq!(
3176            eval.interpret_inline_policy(
3177                &parse_expr(r#""eggs and ham" like "ham*""#).expect("parsing error")
3178            ),
3179            Ok(Value::Lit(Literal::Bool(false)))
3180        );
3181        assert_eq!(
3182            eval.interpret_inline_policy(
3183                &parse_expr(r#""eggs and ham" like "*ham""#).expect("parsing error")
3184            ),
3185            Ok(Value::Lit(Literal::Bool(true)))
3186        );
3187        // "eggs, ham, and spinach" vs "ham"
3188        assert_eq!(
3189            eval.interpret_inline_policy(
3190                &parse_expr(r#""eggs, ham, and spinach" like "ham*""#).expect("parsing error")
3191            ),
3192            Ok(Value::Lit(Literal::Bool(false)))
3193        );
3194        assert_eq!(
3195            eval.interpret_inline_policy(
3196                &parse_expr(r#""eggs, ham, and spinach" like "*ham""#).expect("parsing error")
3197            ),
3198            Ok(Value::Lit(Literal::Bool(false)))
3199        );
3200        assert_eq!(
3201            eval.interpret_inline_policy(
3202                &parse_expr(r#""eggs, ham, and spinach" like "*ham*""#).expect("parsing error")
3203            ),
3204            Ok(Value::Lit(Literal::Bool(true)))
3205        );
3206        // "Gotham" vs "ham"
3207        assert_eq!(
3208            eval.interpret_inline_policy(
3209                &parse_expr(r#""Gotham" like "ham*""#).expect("parsing error")
3210            ),
3211            Ok(Value::Lit(Literal::Bool(false)))
3212        );
3213        assert_eq!(
3214            eval.interpret_inline_policy(
3215                &parse_expr(r#""Gotham" like "*ham""#).expect("parsing error")
3216            ),
3217            Ok(Value::Lit(Literal::Bool(true)))
3218        );
3219        // "ham" vs "ham"
3220        assert_eq!(
3221            eval.interpret_inline_policy(
3222                &parse_expr(r#""ham" like "ham""#).expect("parsing error")
3223            ),
3224            Ok(Value::Lit(Literal::Bool(true)))
3225        );
3226        assert_eq!(
3227            eval.interpret_inline_policy(
3228                &parse_expr(r#""ham" like "ham*""#).expect("parsing error")
3229            ),
3230            Ok(Value::Lit(Literal::Bool(true)))
3231        );
3232        assert_eq!(
3233            eval.interpret_inline_policy(
3234                &parse_expr(r#""ham" like "*ham""#).expect("parsing error")
3235            ),
3236            Ok(Value::Lit(Literal::Bool(true)))
3237        );
3238        assert_eq!(
3239            eval.interpret_inline_policy(
3240                &parse_expr(r#""ham" like "*h*a*m*""#).expect("parsing error")
3241            ),
3242            Ok(Value::Lit(Literal::Bool(true)))
3243        );
3244        // "ham and ham" vs "ham"
3245        assert_eq!(
3246            eval.interpret_inline_policy(
3247                &parse_expr(r#""ham and ham" like "ham*""#).expect("parsing error")
3248            ),
3249            Ok(Value::Lit(Literal::Bool(true)))
3250        );
3251        assert_eq!(
3252            eval.interpret_inline_policy(
3253                &parse_expr(r#""ham and ham" like "*ham""#).expect("parsing error")
3254            ),
3255            Ok(Value::Lit(Literal::Bool(true)))
3256        );
3257        // "ham" vs "ham and eggs"
3258        assert_eq!(
3259            eval.interpret_inline_policy(
3260                &parse_expr(r#""ham" like "*ham and eggs*""#).expect("parsing error")
3261            ),
3262            Ok(Value::Lit(Literal::Bool(false)))
3263        );
3264        // type error
3265        assert_eq!(
3266            eval.interpret_inline_policy(&Expr::like(Expr::val(354), vec![])),
3267            Err(EvaluationError::TypeError {
3268                expected: vec![Type::String],
3269                actual: Type::Long
3270            })
3271        );
3272        // 'contains' is not allowed on strings
3273        assert_eq!(
3274            eval.interpret_inline_policy(&Expr::contains(
3275                Expr::val("ham and ham"),
3276                Expr::val("ham")
3277            )),
3278            Err(EvaluationError::TypeError {
3279                expected: vec![Type::Set],
3280                actual: Type::String
3281            })
3282        );
3283        // '\0' should not match '*'
3284        assert_eq!(
3285            eval.interpret_inline_policy(&Expr::like(
3286                Expr::val("*"),
3287                vec![PatternElem::Char('\u{0000}')]
3288            )),
3289            Ok(Value::Lit(Literal::Bool(false)))
3290        );
3291
3292        assert_eq!(
3293            eval.interpret_inline_policy(
3294                &parse_expr(r#"   "\\afterslash" like "\\*"   "#).expect("parsing error")
3295            ),
3296            Ok(Value::Lit(Literal::Bool(true)))
3297        );
3298    }
3299
3300    #[test]
3301    fn interpret_string_like_escaped_chars() {
3302        let request = basic_request();
3303        let entities = basic_entities();
3304        let exts = Extensions::none();
3305        let eval = Evaluator::new(&request, &entities, &exts).expect("failed to create evaluator");
3306        // testing like wth escaped characters -- similar tests are also in parser/convert.rs
3307        assert_eq!(
3308            eval.interpret_inline_policy(
3309                &parse_expr(r#""string\\with\\backslashes" like "string\\with\\backslashes""#)
3310                    .expect("parsing error")
3311            ),
3312            Ok(Value::Lit(Literal::Bool(true)))
3313        );
3314        assert_eq!(
3315            eval.interpret_inline_policy(
3316                &parse_expr(
3317                    r#""string\\with\\backslashes" like "string\u{0000}with\u{0000}backslashe""#
3318                )
3319                .expect("parsing error")
3320            ),
3321            Ok(Value::Lit(Literal::Bool(false)))
3322        );
3323        assert_eq!(
3324            eval.interpret_inline_policy(
3325                &parse_expr(r#""string\\with\\backslashes" like "string*with*backslashes""#)
3326                    .expect("parsing error")
3327            ),
3328            Ok(Value::Lit(Literal::Bool(true)))
3329        );
3330        assert_eq!(
3331            eval.interpret_inline_policy(
3332                &parse_expr(r#""string*with*stars" like "string\*with\*stars""#)
3333                    .expect("parsing error")
3334            ),
3335            Ok(Value::Lit(Literal::Bool(true)))
3336        );
3337        assert_eq!(eval.interpret_inline_policy(&parse_expr(r#""string\\*with\\*backslashes\\*and\\*stars" like "string\\*with\\*backslashes\\*and\\*stars""#).expect("parsing error")), Ok(Value::Lit(Literal::Bool(true))));
3338    }
3339
3340    #[test]
3341    fn interpret_contains_all_and_contains_any() -> Result<()> {
3342        let request = basic_request();
3343        let entities = basic_entities();
3344        let exts = Extensions::none();
3345        let eval = Evaluator::new(&request, &entities, &exts).expect("failed to create evaluator");
3346        //  [1, -22, 34] containsall of [1, -22]?
3347        assert_eq!(
3348            eval.interpret_inline_policy(&Expr::contains_all(
3349                Expr::set(vec![Expr::val(1), Expr::val(-22), Expr::val(34)]),
3350                Expr::set(vec![Expr::val(1), Expr::val(-22)])
3351            )),
3352            Ok(Value::Lit(Literal::Bool(true)))
3353        );
3354        // [1, -22, 34] containsall [-22, 1]?
3355        assert_eq!(
3356            eval.interpret_inline_policy(&Expr::contains_all(
3357                Expr::set(vec![Expr::val(1), Expr::val(-22), Expr::val(34)]),
3358                Expr::set(vec![Expr::val(-22), Expr::val(1)])
3359            )),
3360            Ok(Value::Lit(Literal::Bool(true)))
3361        );
3362        // [1, -22, 34] containsall [-22]?
3363        assert_eq!(
3364            eval.interpret_inline_policy(&Expr::contains_all(
3365                Expr::set(vec![Expr::val(1), Expr::val(-22), Expr::val(34)]),
3366                Expr::set(vec![Expr::val(-22)])
3367            )),
3368            Ok(Value::Lit(Literal::Bool(true)))
3369        );
3370        // [43, 34] containsall [34, 43]?
3371        assert_eq!(
3372            eval.interpret_inline_policy(&Expr::contains_all(
3373                Expr::set(vec![Expr::val(43), Expr::val(34)]),
3374                Expr::set(vec![Expr::val(34), Expr::val(43)])
3375            )),
3376            Ok(Value::Lit(Literal::Bool(true)))
3377        );
3378        // [1, -2, 34] containsall [1, -22]?
3379        assert_eq!(
3380            eval.interpret_inline_policy(&Expr::contains_all(
3381                Expr::set(vec![Expr::val(1), Expr::val(-2), Expr::val(34)]),
3382                Expr::set(vec![Expr::val(1), Expr::val(-22)])
3383            )),
3384            Ok(Value::Lit(Literal::Bool(false)))
3385        );
3386        // [1, 34] containsall [1, 101, 34]?
3387        assert_eq!(
3388            eval.interpret_inline_policy(&Expr::contains_all(
3389                Expr::set(vec![Expr::val(1), Expr::val(34)]),
3390                Expr::set(vec![Expr::val(1), Expr::val(101), Expr::val(34)])
3391            )),
3392            Ok(Value::Lit(Literal::Bool(false)))
3393        );
3394        // [1, 34, 102] containsall [1, 101, 34]?
3395        assert_eq!(
3396            eval.interpret_inline_policy(&Expr::contains_all(
3397                Expr::set(vec![Expr::val(1), Expr::val(34), Expr::val(102)]),
3398                Expr::set(vec![Expr::val(1), Expr::val(101), Expr::val(34)])
3399            )),
3400            Ok(Value::Lit(Literal::Bool(false)))
3401        );
3402        // [2, -7, 387] containsall [1, 101, 34]?
3403        assert_eq!(
3404            eval.interpret_inline_policy(&Expr::contains_all(
3405                Expr::set(vec![Expr::val(2), Expr::val(-7), Expr::val(387)]),
3406                Expr::set(vec![Expr::val(1), Expr::val(101), Expr::val(34)])
3407            )),
3408            Ok(Value::Lit(Literal::Bool(false)))
3409        );
3410        // [2, 43] containsall []?
3411        assert_eq!(
3412            eval.interpret_inline_policy(&Expr::contains_all(
3413                Expr::set(vec![Expr::val(2), Expr::val(43)]),
3414                Expr::set(vec![])
3415            )),
3416            Ok(Value::Lit(Literal::Bool(true)))
3417        );
3418        // [] containsall [2, 43]?
3419        assert_eq!(
3420            eval.interpret_inline_policy(&Expr::contains_all(
3421                Expr::set(vec![]),
3422                Expr::set(vec![Expr::val(2), Expr::val(43)])
3423            )),
3424            Ok(Value::Lit(Literal::Bool(false)))
3425        );
3426        // [<entity bar>, <entity foo>] containsall [<entity foo>]?
3427        assert_eq!(
3428            eval.interpret_inline_policy(&Expr::contains_all(
3429                Expr::set(vec![
3430                    Expr::val(EntityUID::with_eid("bar")),
3431                    Expr::val(EntityUID::with_eid("foo"))
3432                ]),
3433                Expr::set(vec![Expr::val(EntityUID::with_eid("foo"))])
3434            )),
3435            Ok(Value::Lit(Literal::Bool(true)))
3436        );
3437        // [false, 3, [47, 0], {"2": "ham"}] containsall [3, {"2": "ham"}]?
3438        assert_eq!(
3439            eval.interpret_inline_policy(&Expr::contains_all(
3440                Expr::set(vec![
3441                    Expr::val(false),
3442                    Expr::val(3),
3443                    Expr::set(vec![Expr::val(47), Expr::val(0)]),
3444                    Expr::record(vec![("2".into(), Expr::val("ham"))])
3445                ]),
3446                Expr::set(vec![
3447                    Expr::val(3),
3448                    Expr::record(vec![("2".into(), Expr::val("ham"))])
3449                ])
3450            )),
3451            Ok(Value::Lit(Literal::Bool(true)))
3452        );
3453        //  "ham and eggs" containsall "ham"?
3454        assert_eq!(
3455            eval.interpret_inline_policy(&Expr::contains_all(
3456                Expr::val("ham"),
3457                Expr::val("ham and eggs")
3458            )),
3459            Err(EvaluationError::TypeError {
3460                expected: vec![Type::Set],
3461                actual: Type::String
3462            })
3463        );
3464        // {"2": "ham", "3": "eggs"} containsall {"2": "ham"} ?
3465        assert_eq!(
3466            eval.interpret_inline_policy(&Expr::contains_all(
3467                Expr::record(vec![("2".into(), Expr::val("ham"))]),
3468                Expr::record(vec![
3469                    ("2".into(), Expr::val("ham")),
3470                    ("3".into(), Expr::val("eggs"))
3471                ])
3472            )),
3473            Err(EvaluationError::TypeError {
3474                expected: vec![Type::Set],
3475                actual: Type::Record
3476            })
3477        );
3478        // test for [1, -22] contains_any of [1, -22, 34]
3479        assert_eq!(
3480            eval.interpret_inline_policy(&Expr::contains_any(
3481                Expr::set(vec![Expr::val(1), Expr::val(-22)]),
3482                Expr::set(vec![Expr::val(1), Expr::val(-22), Expr::val(34)])
3483            )),
3484            Ok(Value::Lit(Literal::Bool(true)))
3485        );
3486        // test for [1, -22, 34] contains_any of [1, -22]
3487        assert_eq!(
3488            eval.interpret_inline_policy(&Expr::contains_any(
3489                Expr::set(vec![Expr::val(1), Expr::val(-22), Expr::val(34)]),
3490                Expr::set(vec![Expr::val(1), Expr::val(-22)])
3491            )),
3492            Ok(Value::Lit(Literal::Bool(true)))
3493        );
3494        // test for [-22] contains_any of [1, -22, 34]
3495        assert_eq!(
3496            eval.interpret_inline_policy(&Expr::contains_any(
3497                Expr::set(vec![Expr::val(-22)]),
3498                Expr::set(vec![Expr::val(1), Expr::val(-22), Expr::val(34)])
3499            )),
3500            Ok(Value::Lit(Literal::Bool(true)))
3501        );
3502        // test for [1, 101] contains_any of [1, -22, 34]
3503        assert_eq!(
3504            eval.interpret_inline_policy(&Expr::contains_any(
3505                Expr::set(vec![Expr::val(1), Expr::val(101)]),
3506                Expr::set(vec![Expr::val(1), Expr::val(-22), Expr::val(34)])
3507            )),
3508            Ok(Value::Lit(Literal::Bool(true)))
3509        );
3510        // test for [1, 101] contains_any of [-22, 34]
3511        assert_eq!(
3512            eval.interpret_inline_policy(&Expr::contains_any(
3513                Expr::set(vec![Expr::val(1), Expr::val(101)]),
3514                Expr::set(vec![Expr::val(-22), Expr::val(34)])
3515            )),
3516            Ok(Value::Lit(Literal::Bool(false)))
3517        );
3518        // test for [] contains_any of [-22, 34]
3519        assert_eq!(
3520            eval.interpret_inline_policy(&Expr::contains_any(
3521                Expr::set(vec![]),
3522                Expr::set(vec![Expr::val(-22), Expr::val(34)])
3523            )),
3524            Ok(Value::Lit(Literal::Bool(false)))
3525        );
3526        // test for [-22, 34] contains_any of []
3527        assert_eq!(
3528            eval.interpret_inline_policy(&Expr::contains_any(
3529                Expr::set(vec![Expr::val(-22), Expr::val(34)]),
3530                Expr::set(vec![])
3531            )),
3532            Ok(Value::Lit(Literal::Bool(false)))
3533        );
3534        // test for [<entity foo>, <entity bar>] contains_any of [<entity ham>, <entity eggs>]
3535        assert_eq!(
3536            eval.interpret_inline_policy(&Expr::contains_any(
3537                Expr::set(vec![
3538                    Expr::val(EntityUID::with_eid("foo")),
3539                    Expr::val(EntityUID::with_eid("bar"))
3540                ]),
3541                Expr::set(vec![
3542                    Expr::val(EntityUID::with_eid("ham")),
3543                    Expr::val(EntityUID::with_eid("eggs"))
3544                ])
3545            )),
3546            Ok(Value::Lit(Literal::Bool(false)))
3547        );
3548        // test for [3, {"2": "ham", "1": "eggs"}] contains_any of [7, false, [-22, true], {"1": "eggs", "2": "ham"}]
3549        assert_eq!(
3550            eval.interpret_inline_policy(&Expr::contains_any(
3551                Expr::set(vec![
3552                    Expr::val(3),
3553                    Expr::record(vec![
3554                        ("2".into(), Expr::val("ham")),
3555                        ("1".into(), Expr::val("eggs"))
3556                    ])
3557                ]),
3558                Expr::set(vec![
3559                    Expr::val(7),
3560                    Expr::val(false),
3561                    Expr::set(vec![Expr::val(-22), Expr::val(true)]),
3562                    Expr::record(vec![
3563                        ("1".into(), Expr::val("eggs")),
3564                        ("2".into(), Expr::val("ham"))
3565                    ])
3566                ])
3567            )),
3568            Ok(Value::Lit(Literal::Bool(true)))
3569        );
3570        // test for "ham" contains_any of "ham and eggs"
3571        assert_eq!(
3572            eval.interpret_inline_policy(&Expr::contains_any(
3573                Expr::val("ham"),
3574                Expr::val("ham and eggs")
3575            )),
3576            Err(EvaluationError::TypeError {
3577                expected: vec![Type::Set],
3578                actual: Type::String
3579            })
3580        );
3581        // test for {"2": "ham"} contains_any of {"2": "ham", "3": "eggs"}
3582        assert_eq!(
3583            eval.interpret_inline_policy(&Expr::contains_any(
3584                Expr::record(vec![("2".into(), Expr::val("ham"))]),
3585                Expr::record(vec![
3586                    ("2".into(), Expr::val("ham")),
3587                    ("3".into(), Expr::val("eggs"))
3588                ])
3589            )),
3590            Err(EvaluationError::TypeError {
3591                expected: vec![Type::Set],
3592                actual: Type::Record
3593            })
3594        );
3595        Ok(())
3596    }
3597
3598    #[test]
3599    fn eval_and_or() -> Result<()> {
3600        use crate::parser;
3601        let request = basic_request();
3602        let eparser: EntityJsonParser<'_, '_> =
3603            EntityJsonParser::new(None, Extensions::none(), TCComputation::ComputeNow);
3604        let entities = eparser.from_json_str("[]").expect("empty slice");
3605        let exts = Extensions::none();
3606        let evaluator = Evaluator::new(&request, &entities, &exts).expect("empty slice");
3607
3608        // short-circuit allows these to pass without error
3609        let raw_expr = "(false && 3)";
3610        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3611        assert!(evaluator.interpret_inline_policy(&expr).is_ok());
3612
3613        let raw_expr = "(true || 3)";
3614        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3615        assert!(evaluator.interpret_inline_policy(&expr).is_ok());
3616
3617        // short-circuit plus total equality allows these to pass without error
3618        let raw_expr = "(false && 3) == 3";
3619        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3620        assert!(evaluator.interpret_inline_policy(&expr).is_ok());
3621
3622        let raw_expr = "(true || 3) == 3";
3623        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3624        assert!(evaluator.interpret_inline_policy(&expr).is_ok());
3625
3626        let raw_expr = "(false && 3 && true) == 3";
3627        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3628        assert!(evaluator.interpret_inline_policy(&expr).is_ok());
3629
3630        let raw_expr = "(true || 3 || true) == 3";
3631        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3632        assert!(evaluator.interpret_inline_policy(&expr).is_ok());
3633
3634        // These must error
3635        let raw_expr = "(true && 3)";
3636        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3637        let t = evaluator.interpret_inline_policy(&expr);
3638        println!("EXPR={:?}", t);
3639        assert!(evaluator.interpret_inline_policy(&expr).is_err());
3640
3641        let raw_expr = "(3 && true)";
3642        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3643        assert!(evaluator.interpret_inline_policy(&expr).is_err());
3644
3645        let raw_expr = "(3 && false)";
3646        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3647        assert!(evaluator.interpret_inline_policy(&expr).is_err());
3648
3649        let raw_expr = "(3 || true)";
3650        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3651        assert!(evaluator.interpret_inline_policy(&expr).is_err());
3652
3653        let raw_expr = "(3 || false)";
3654        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3655        assert!(evaluator.interpret_inline_policy(&expr).is_err());
3656
3657        let raw_expr = "(false || 3)";
3658        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3659        assert!(evaluator.interpret_inline_policy(&expr).is_err());
3660
3661        let raw_expr = "(true && 3) == 3";
3662        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3663        assert!(evaluator.interpret_inline_policy(&expr).is_err());
3664
3665        let raw_expr = "(3 && true) == 3";
3666        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3667        assert!(evaluator.interpret_inline_policy(&expr).is_err());
3668
3669        let raw_expr = "(3 && false) == 3";
3670        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3671        assert!(evaluator.interpret_inline_policy(&expr).is_err());
3672
3673        let raw_expr = "(3 || true) == 3";
3674        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3675        assert!(evaluator.interpret_inline_policy(&expr).is_err());
3676
3677        let raw_expr = "(3 || false) == 3";
3678        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3679        assert!(evaluator.interpret_inline_policy(&expr).is_err());
3680
3681        let raw_expr = "(false || 3) == 3";
3682        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3683        assert!(evaluator.interpret_inline_policy(&expr).is_err());
3684
3685        let raw_expr = "(true && 3 && true) == 3";
3686        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3687        assert!(evaluator.interpret_inline_policy(&expr).is_err());
3688
3689        let raw_expr = "(3 && true && true) == 3";
3690        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3691        assert!(evaluator.interpret_inline_policy(&expr).is_err());
3692
3693        let raw_expr = "(3 && false && true) == 3";
3694        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3695        assert!(evaluator.interpret_inline_policy(&expr).is_err());
3696
3697        let raw_expr = "(3 || true || true) == 3";
3698        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3699        assert!(evaluator.interpret_inline_policy(&expr).is_err());
3700
3701        let raw_expr = "(3 || false || true) == 3";
3702        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3703        assert!(evaluator.interpret_inline_policy(&expr).is_err());
3704
3705        let raw_expr = "(false || 3 || true) == 3";
3706        let expr = parser::parse_expr(raw_expr).expect("parse fail");
3707        assert!(evaluator.interpret_inline_policy(&expr).is_err());
3708
3709        Ok(())
3710    }
3711
3712    #[test]
3713    fn template_env_tests() {
3714        let request = basic_request();
3715        let eparser: EntityJsonParser<'_, '_> =
3716            EntityJsonParser::new(None, Extensions::none(), TCComputation::ComputeNow);
3717        let entities = eparser.from_json_str("[]").expect("empty slice");
3718        let exts = Extensions::none();
3719        let evaluator = Evaluator::new(&request, &entities, &exts).expect("empty slice");
3720        let e = Expr::slot(SlotId::principal());
3721
3722        let slots = HashMap::new();
3723        let r = evaluator.partial_interpret(&e, &slots);
3724        match r {
3725            Err(EvaluationError::TemplateInstantiationError(slotid)) => {
3726                assert_eq!(slotid, SlotId::principal())
3727            }
3728            Err(e) => panic!("Got wrong error: {e}"),
3729            Ok(v) => panic!("Got wrong response: {v}"),
3730        };
3731
3732        let mut slots = HashMap::new();
3733        slots.insert(SlotId::principal(), EntityUID::with_eid("eid"));
3734        let r = evaluator.partial_interpret(&e, &slots);
3735        match r {
3736            Ok(e) => assert_eq!(
3737                e,
3738                PartialValue::Value(Value::Lit(Literal::EntityUID(Arc::new(
3739                    EntityUID::with_eid("eid")
3740                ))))
3741            ),
3742            Err(e) => panic!("Got unexpected error {e}"),
3743        };
3744    }
3745
3746    #[test]
3747    fn template_interp() {
3748        let t = parse_policy_template(
3749            Some("template".to_string()),
3750            r#"permit(principal == ?principal, action, resource);"#,
3751        )
3752        .expect("Parse Error");
3753        let mut pset = PolicySet::new();
3754        pset.add_template(t)
3755            .expect("Template already present in PolicySet");
3756        let mut values = HashMap::new();
3757        values.insert(SlotId::principal(), EntityUID::with_eid("p"));
3758        pset.link(
3759            PolicyID::from_string("template"),
3760            PolicyID::from_string("instance"),
3761            values,
3762        )
3763        .expect("Instantiation failed!");
3764        let q = Request::new(
3765            EntityUID::with_eid("p"),
3766            EntityUID::with_eid("a"),
3767            EntityUID::with_eid("r"),
3768            Context::empty(),
3769        );
3770        let eparser: EntityJsonParser<'_, '_> =
3771            EntityJsonParser::new(None, Extensions::none(), TCComputation::ComputeNow);
3772        let entities = eparser.from_json_str("[]").expect("empty slice");
3773        let exts = Extensions::none();
3774        let eval = Evaluator::new(&q, &entities, &exts).expect("Failed to start evaluator");
3775
3776        let ir = pset.policies().next().expect("No linked policies");
3777        assert!(
3778            match eval.partial_evaluate(ir).expect("evaluation_failed") {
3779                Either::Left(b) => b,
3780                Either::Right(_) => false,
3781            },
3782            "Should be enforced"
3783        );
3784    }
3785
3786    #[test]
3787    fn restricted_expressions() {
3788        let exts = Extensions::all_available();
3789        let evaluator = RestrictedEvaluator::new(&exts);
3790
3791        // simple expressions
3792        assert_eq!(
3793            BorrowedRestrictedExpr::new(&Expr::val(true))
3794                .map_err(Into::into)
3795                .and_then(|e| evaluator.partial_interpret(e)),
3796            Ok(Value::from(true).into())
3797        );
3798        assert_eq!(
3799            BorrowedRestrictedExpr::new(&Expr::val(-2))
3800                .map_err(Into::into)
3801                .and_then(|e| evaluator.partial_interpret(e)),
3802            Ok(Value::from(-2).into())
3803        );
3804        assert_eq!(
3805            BorrowedRestrictedExpr::new(&Expr::val("hello world"))
3806                .map_err(Into::into)
3807                .and_then(|e| evaluator.partial_interpret(e)),
3808            Ok(Value::from("hello world").into())
3809        );
3810        assert_eq!(
3811            BorrowedRestrictedExpr::new(&Expr::val(EntityUID::with_eid("alice")))
3812                .map_err(Into::into)
3813                .and_then(|e| evaluator.partial_interpret(e)),
3814            Ok(Value::from(EntityUID::with_eid("alice")).into())
3815        );
3816        assert!(matches!(
3817            BorrowedRestrictedExpr::new(&Expr::var(Var::Principal))
3818                .map_err(Into::into)
3819                .and_then(|e| evaluator.partial_interpret(e)),
3820            Err(EvaluationError::InvalidRestrictedExpression { .. })
3821        ));
3822        assert!(matches!(
3823            BorrowedRestrictedExpr::new(&Expr::var(Var::Action))
3824                .map_err(Into::into)
3825                .and_then(|e| evaluator.partial_interpret(e)),
3826            Err(EvaluationError::InvalidRestrictedExpression { .. })
3827        ));
3828        assert!(matches!(
3829            BorrowedRestrictedExpr::new(&Expr::var(Var::Resource))
3830                .map_err(Into::into)
3831                .and_then(|e| evaluator.partial_interpret(e)),
3832            Err(EvaluationError::InvalidRestrictedExpression { .. })
3833        ));
3834        assert!(matches!(
3835            BorrowedRestrictedExpr::new(&Expr::var(Var::Context))
3836                .map_err(Into::into)
3837                .and_then(|e| evaluator.partial_interpret(e)),
3838            Err(EvaluationError::InvalidRestrictedExpression { .. })
3839        ));
3840        assert!(matches!(
3841            BorrowedRestrictedExpr::new(&Expr::ite(Expr::val(true), Expr::val(7), Expr::val(12)),)
3842                .map_err(Into::into)
3843                .and_then(|e| evaluator.partial_interpret(e)),
3844            Err(EvaluationError::InvalidRestrictedExpression { .. })
3845        ));
3846        assert!(matches!(
3847            BorrowedRestrictedExpr::new(&Expr::and(Expr::val("bogus"), Expr::val(true)))
3848                .map_err(Into::into)
3849                .and_then(|e| evaluator.partial_interpret(e)),
3850            Err(EvaluationError::InvalidRestrictedExpression { .. })
3851        ));
3852        assert!(matches!(
3853            BorrowedRestrictedExpr::new(&Expr::or(Expr::val("bogus"), Expr::val(true)))
3854                .map_err(Into::into)
3855                .and_then(|e| evaluator.partial_interpret(e)),
3856            Err(EvaluationError::InvalidRestrictedExpression { .. })
3857        ));
3858        assert!(matches!(
3859            BorrowedRestrictedExpr::new(&Expr::not(Expr::val(true)))
3860                .map_err(Into::into)
3861                .and_then(|e| evaluator.partial_interpret(e)),
3862            Err(EvaluationError::InvalidRestrictedExpression { .. })
3863        ));
3864        assert!(matches!(
3865            BorrowedRestrictedExpr::new(&Expr::is_in(
3866                Expr::val(EntityUID::with_eid("alice")),
3867                Expr::val(EntityUID::with_eid("some_group"))
3868            ))
3869            .map_err(Into::into)
3870            .and_then(|e| evaluator.partial_interpret(e)),
3871            Err(EvaluationError::InvalidRestrictedExpression { .. })
3872        ));
3873        assert!(matches!(
3874            BorrowedRestrictedExpr::new(&Expr::is_eq(
3875                Expr::val(EntityUID::with_eid("alice")),
3876                Expr::val(EntityUID::with_eid("some_group"))
3877            ))
3878            .map_err(Into::into)
3879            .and_then(|e| evaluator.partial_interpret(e)),
3880            Err(EvaluationError::InvalidRestrictedExpression { .. })
3881        ));
3882        assert!(matches!(
3883            BorrowedRestrictedExpr::new(&Expr::call_extension_fn(
3884                "ip".parse().expect("should be a valid Name"),
3885                vec![Expr::val("222.222.222.222")]
3886            ))
3887            .map_err(Into::into)
3888            .and_then(|e| evaluator.partial_interpret(e)),
3889            Ok(PartialValue::Value(Value::ExtensionValue(_)))
3890        ));
3891        assert!(matches!(
3892            BorrowedRestrictedExpr::new(&Expr::get_attr(
3893                Expr::val(EntityUID::with_eid("alice")),
3894                "pancakes".into()
3895            ),)
3896            .map_err(Into::into)
3897            .and_then(|e| evaluator.partial_interpret(e)),
3898            Err(EvaluationError::InvalidRestrictedExpression { .. })
3899        ));
3900        assert!(matches!(
3901            BorrowedRestrictedExpr::new(&Expr::has_attr(
3902                Expr::val(EntityUID::with_eid("alice")),
3903                "pancakes".into()
3904            ),)
3905            .map_err(Into::into)
3906            .and_then(|e| evaluator.partial_interpret(e)),
3907            Err(EvaluationError::InvalidRestrictedExpression { .. })
3908        ));
3909        assert!(matches!(
3910            BorrowedRestrictedExpr::new(&Expr::like(
3911                Expr::val("abcdefg12"),
3912                vec![
3913                    PatternElem::Char('a'),
3914                    PatternElem::Char('b'),
3915                    PatternElem::Char('c'),
3916                    PatternElem::Wildcard
3917                ]
3918            ),)
3919            .map_err(Into::into)
3920            .and_then(|e| evaluator.partial_interpret(e)),
3921            Err(EvaluationError::InvalidRestrictedExpression { .. })
3922        ));
3923        assert!(matches!(
3924            BorrowedRestrictedExpr::new(&Expr::set([Expr::val("hi"), Expr::val("there")]))
3925                .map_err(Into::into)
3926                .and_then(|e| evaluator.partial_interpret(e)),
3927            Ok(PartialValue::Value(Value::Set(_)))
3928        ));
3929        assert!(matches!(
3930            BorrowedRestrictedExpr::new(&Expr::record([
3931                ("hi".into(), Expr::val(1001)),
3932                ("foo".into(), Expr::val("bar"))
3933            ]),)
3934            .map_err(Into::into)
3935            .and_then(|e| evaluator.partial_interpret(e)),
3936            Ok(PartialValue::Value(Value::Record(_)))
3937        ));
3938
3939        // complex expressions -- for instance, violation not at top level
3940        assert!(matches!(
3941            BorrowedRestrictedExpr::new(&Expr::set([
3942                Expr::val("hi"),
3943                Expr::and(Expr::val("bogus"), Expr::val(false))
3944            ]),)
3945            .map_err(Into::into)
3946            .and_then(|e| evaluator.partial_interpret(e)),
3947            Err(EvaluationError::InvalidRestrictedExpression { .. })
3948        ));
3949        assert!(matches!(
3950            BorrowedRestrictedExpr::new(&Expr::call_extension_fn(
3951                "ip".parse().expect("should be a valid Name"),
3952                vec![Expr::var(Var::Principal)],
3953            ),)
3954            .map_err(Into::into)
3955            .and_then(|e| evaluator.partial_interpret(e)),
3956            Err(EvaluationError::InvalidRestrictedExpression { .. })
3957        ));
3958    }
3959
3960    #[test]
3961    fn simple_partial() {
3962        let pset = parse_policyset(
3963            r#"
3964            permit(principal == Principal::"alice", action, resource);
3965            "#,
3966        )
3967        .expect("Failed to parse");
3968        let euid =
3969            Arc::new(EntityUID::from_str(r#"Principal::"alice""#).expect("EUID failed to parse"));
3970        let p = pset
3971            .get(&PolicyID::from_string("policy0"))
3972            .expect("No such policy");
3973        let q = Request::new_with_unknowns(
3974            EntityUIDEntry::Unknown,
3975            EntityUIDEntry::Unknown,
3976            EntityUIDEntry::Unknown,
3977            Some(Context::empty()),
3978        );
3979        let es = Entities::new();
3980        let exts = Extensions::none();
3981        let e = Evaluator::new(&q, &es, &exts).expect("failed to create evaluator");
3982        match e.partial_evaluate(p).expect("eval error") {
3983            Either::Left(_) => panic!("Evalled to a value"),
3984            Either::Right(expr) => {
3985                println!("{expr}");
3986                assert!(expr.is_unknown());
3987                let m: HashMap<_, _> = [("principal".into(), Value::Lit(Literal::EntityUID(euid)))]
3988                    .into_iter()
3989                    .collect();
3990                let new_expr = expr.substitute(&m).unwrap();
3991                assert_eq!(
3992                    e.partial_interpret(&new_expr, &HashMap::new())
3993                        .expect("Failed to eval"),
3994                    PartialValue::Value(true.into())
3995                );
3996            }
3997        }
3998    }
3999
4000    fn partial_context_test(context_expr: Expr, e: Expr) -> Either<Value, Expr> {
4001        let euid: EntityUID = r#"Test::"test""#.parse().unwrap();
4002        let rexpr = RestrictedExpr::new(context_expr)
4003            .expect("Context Expression was not a restricted expression");
4004        let context = Context::from_expr(rexpr);
4005        let q = Request::new(euid.clone(), euid.clone(), euid, context);
4006        let es = Entities::new();
4007        let exts = Extensions::none();
4008        let eval = Evaluator::new(&q, &es, &exts).expect("Failed to instantiate evaluator");
4009        eval.partial_eval_expr(&e).unwrap()
4010    }
4011
4012    #[test]
4013    fn partial_contexts1() {
4014        // { "cell" : <unknown> }
4015        let c_expr = Expr::record([("cell".into(), Expr::unknown("cell"))]);
4016        let expr = Expr::binary_app(
4017            BinaryOp::Eq,
4018            Expr::get_attr(Expr::var(Var::Context), "cell".into()),
4019            Expr::val(2),
4020        );
4021        let expected = Expr::binary_app(
4022            BinaryOp::Eq,
4023            Expr::unknown("cell".to_string()),
4024            Expr::val(2),
4025        );
4026
4027        let r = partial_context_test(c_expr, expr);
4028
4029        assert_eq!(r, Either::Right(expected));
4030    }
4031
4032    #[test]
4033    fn partial_contexts2() {
4034        // { "loc" : "test", "cell" : <unknown> }
4035        let c_expr = Expr::record([
4036            ("loc".into(), Expr::val("test")),
4037            ("cell".into(), Expr::unknown("cell")),
4038        ]);
4039        // context["cell"] == 2
4040        let expr = Expr::binary_app(
4041            BinaryOp::Eq,
4042            Expr::get_attr(Expr::var(Var::Context), "cell".into()),
4043            Expr::val(2),
4044        );
4045        let r = partial_context_test(c_expr.clone(), expr);
4046        let expected = Expr::binary_app(
4047            BinaryOp::Eq,
4048            Expr::unknown("cell".to_string()),
4049            Expr::val(2),
4050        );
4051        assert_eq!(r, Either::Right(expected));
4052
4053        // context["loc"] == 2
4054        let expr = Expr::binary_app(
4055            BinaryOp::Eq,
4056            Expr::get_attr(Expr::var(Var::Context), "loc".into()),
4057            Expr::val(2),
4058        );
4059        let r = partial_context_test(c_expr, expr);
4060        assert_eq!(r, Either::Left(false.into()));
4061    }
4062
4063    #[test]
4064    fn partial_contexts3() {
4065        // { "loc" : "test", "cell" : { "row" : <unknown> } }
4066        let row = Expr::record([("row".into(), Expr::unknown("row"))]);
4067        //assert!(row.is_partially_projectable());
4068        let c_expr = Expr::record([("loc".into(), Expr::val("test")), ("cell".into(), row)]);
4069        //assert!(c_expr.is_partially_projectable());
4070        // context["cell"]["row"] == 2
4071        let expr = Expr::binary_app(
4072            BinaryOp::Eq,
4073            Expr::get_attr(
4074                Expr::get_attr(Expr::var(Var::Context), "cell".into()),
4075                "row".into(),
4076            ),
4077            Expr::val(2),
4078        );
4079        let r = partial_context_test(c_expr, expr);
4080        let expected =
4081            Expr::binary_app(BinaryOp::Eq, Expr::unknown("row".to_string()), Expr::val(2));
4082        assert_eq!(r, Either::Right(expected));
4083    }
4084
4085    #[test]
4086    fn partial_contexts4() {
4087        // { "loc" : "test", "cell" : { "row" : <unknown>, "col" : <unknown> } }
4088        let row = Expr::record([
4089            ("row".into(), Expr::unknown("row")),
4090            ("col".into(), Expr::unknown("col")),
4091        ]);
4092        //assert!(row.is_partially_projectable());
4093        let c_expr = Expr::record([("loc".into(), Expr::val("test")), ("cell".into(), row)]);
4094        //assert!(c_expr.is_partially_projectable());
4095        // context["cell"]["row"] == 2
4096        let expr = Expr::binary_app(
4097            BinaryOp::Eq,
4098            Expr::get_attr(
4099                Expr::get_attr(Expr::var(Var::Context), "cell".into()),
4100                "row".into(),
4101            ),
4102            Expr::val(2),
4103        );
4104        let r = partial_context_test(c_expr.clone(), expr);
4105        let expected = Expr::binary_app(BinaryOp::Eq, Expr::unknown("row"), Expr::val(2));
4106        assert_eq!(r, Either::Right(expected));
4107        // context["cell"]["col"] == 2
4108        let expr = Expr::binary_app(
4109            BinaryOp::Eq,
4110            Expr::get_attr(
4111                Expr::get_attr(Expr::var(Var::Context), "cell".into()),
4112                "col".into(),
4113            ),
4114            Expr::val(2),
4115        );
4116        let r = partial_context_test(c_expr, expr);
4117        let expected =
4118            Expr::binary_app(BinaryOp::Eq, Expr::unknown("col".to_string()), Expr::val(2));
4119        assert_eq!(r, Either::Right(expected));
4120    }
4121
4122    #[test]
4123    fn partial_context_fail() {
4124        let context = Context::from_expr(RestrictedExpr::new_unchecked(Expr::record([
4125            ("a".into(), Expr::val(3)),
4126            ("b".into(), Expr::unknown("b".to_string())),
4127        ])));
4128        let euid: EntityUID = r#"Test::"test""#.parse().unwrap();
4129        let q = Request::new(euid.clone(), euid.clone(), euid, context);
4130        let es = Entities::new();
4131        let exts = Extensions::none();
4132        let eval = Evaluator::new(&q, &es, &exts).expect("Failed to instantiate evaluator");
4133        let e = Expr::get_attr(Expr::var(Var::Context), "foo".into());
4134        assert!(eval.partial_eval_expr(&e).is_err())
4135    }
4136
4137    #[test]
4138    fn mikes_test() {
4139        let policyset = parse_policyset(
4140            r#"
4141            permit(
4142                principal == Principal::"p",
4143                action == Action::"a",
4144                resource == Table::"t"
4145            ) when {
4146                context.cell.row > 5 && context.cell.col < 2
4147            };
4148        "#,
4149        )
4150        .expect("Failed to parse");
4151        let policy = policyset
4152            .get(&PolicyID::from_string("policy0"))
4153            .expect("No such policy");
4154
4155        let es = Entities::new();
4156
4157        let p: EntityUID = r#"Principal::"p""#.parse().expect("Failed to parse");
4158        let a: EntityUID = r#"Action::"a""#.parse().expect("Failed to parse");
4159        let r: EntityUID = r#"Table::"t""#.parse().expect("Failed to parse");
4160
4161        let c_expr = RestrictedExpr::new(Expr::record([(
4162            "cell".into(),
4163            Expr::unknown("cell".to_string()),
4164        )]))
4165        .expect("should qualify as restricted");
4166        let context = Context::from_expr(c_expr);
4167
4168        let q = Request::new(p, a, r, context);
4169        let exts = Extensions::none();
4170        let eval = Evaluator::new(&q, &es, &exts).expect("Could not create evaluator");
4171
4172        let result = eval.partial_evaluate(policy).expect("Eval error");
4173        match result {
4174            Either::Left(_) => panic!("Got a value"),
4175            Either::Right(r) => {
4176                println!("{r}");
4177            }
4178        }
4179    }
4180
4181    fn empty_request() -> Request {
4182        let p: EntityUID = r#"p::"Principal""#.parse().unwrap();
4183        let a: EntityUID = r#"a::"Action""#.parse().unwrap();
4184        let r: EntityUID = r#"r::"Resource""#.parse().unwrap();
4185        let c = Context::empty();
4186        Request::new(p, a, r, c)
4187    }
4188
4189    #[test]
4190    fn if_semantics_residual_guard() {
4191        let a = Expr::unknown("guard".to_string());
4192        let b = Expr::and(Expr::val(1), Expr::val(2));
4193        let c = Expr::val(true);
4194
4195        let e = Expr::ite(a, b, c);
4196
4197        let es = Entities::new();
4198
4199        let exts = Extensions::none();
4200        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4201
4202        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4203
4204        assert_eq!(
4205            r,
4206            PartialValue::Residual(Expr::ite(
4207                Expr::unknown("guard".to_string()),
4208                Expr::call_extension_fn(
4209                    "error".parse().unwrap(),
4210                    vec![Expr::val("type error: expected bool, got long")]
4211                ),
4212                Expr::val(true)
4213            ))
4214        )
4215    }
4216
4217    #[test]
4218    fn if_semantics_both_err() {
4219        let a = Expr::unknown("guard".to_string());
4220        let b = Expr::and(Expr::val(1), Expr::val(2));
4221        let c = Expr::or(Expr::val(1), Expr::val(3));
4222
4223        let e = Expr::ite(a, b, c);
4224
4225        let es = Entities::new();
4226
4227        let exts = Extensions::none();
4228        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4229
4230        assert!(eval.partial_interpret(&e, &HashMap::new()).is_err());
4231    }
4232
4233    #[test]
4234    fn and_semantics1() {
4235        // Left-hand-side evaluates to `false`, should short-circuit to value
4236        let e = Expr::and(
4237            Expr::binary_app(BinaryOp::Eq, Expr::val(1), Expr::val(2)),
4238            Expr::and(Expr::unknown("a".to_string()), Expr::val(false)),
4239        );
4240
4241        let es = Entities::new();
4242        let exts = Extensions::none();
4243        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4244
4245        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4246
4247        assert_eq!(r, PartialValue::Value(Value::Lit(Literal::Bool(false))));
4248    }
4249
4250    #[test]
4251    fn and_semantics2() {
4252        // Left hand sides evaluates to `true`, can't drop it due to dynamic types
4253        let e = Expr::and(
4254            Expr::binary_app(BinaryOp::Eq, Expr::val(2), Expr::val(2)),
4255            Expr::and(Expr::unknown("a".to_string()), Expr::val(false)),
4256        );
4257
4258        let es = Entities::new();
4259        let exts = Extensions::none();
4260        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4261
4262        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4263
4264        assert_eq!(
4265            r,
4266            PartialValue::Residual(Expr::and(
4267                Expr::val(true),
4268                Expr::and(Expr::unknown("a".to_string()), Expr::val(false))
4269            ))
4270        );
4271    }
4272
4273    #[test]
4274    fn and_semantics3() {
4275        // Errors on left hand side should propagate
4276        let e = Expr::and(
4277            Expr::binary_app(BinaryOp::Add, Expr::val("hello"), Expr::val(2)),
4278            Expr::and(Expr::unknown("a".to_string()), Expr::val(false)),
4279        );
4280
4281        let es = Entities::new();
4282        let exts = Extensions::none();
4283        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4284
4285        assert!(eval.partial_interpret(&e, &HashMap::new()).is_err());
4286    }
4287
4288    #[test]
4289    fn and_semantics4() {
4290        // Left hand is residual, errors on right hand side should _not_ propagate
4291        let e = Expr::and(
4292            Expr::binary_app(BinaryOp::Eq, Expr::unknown("a".to_string()), Expr::val(2)),
4293            Expr::and(Expr::val("hello"), Expr::val("bye")),
4294        );
4295
4296        let es = Entities::new();
4297        let exts = Extensions::none();
4298        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4299
4300        assert!(eval.partial_interpret(&e, &HashMap::new()).is_ok());
4301    }
4302
4303    #[test]
4304    fn or_semantics1() {
4305        // Left-hand-side evaluates to `true`, should short-circuit to value
4306
4307        let e = Expr::or(
4308            Expr::binary_app(BinaryOp::Eq, Expr::val(2), Expr::val(2)),
4309            Expr::and(Expr::unknown("a".to_string()), Expr::val(false)),
4310        );
4311
4312        let es = Entities::new();
4313        let exts = Extensions::none();
4314        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4315
4316        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4317
4318        assert_eq!(r, PartialValue::Value(Value::Lit(Literal::Bool(true))));
4319    }
4320
4321    #[test]
4322    fn or_semantics2() {
4323        // Left hand sides evaluates to `false`, can't drop it due to dynamic types
4324        let e = Expr::or(
4325            Expr::binary_app(BinaryOp::Eq, Expr::val(1), Expr::val(2)),
4326            Expr::and(Expr::unknown("a".to_string()), Expr::val(false)),
4327        );
4328
4329        let es = Entities::new();
4330        let exts = Extensions::none();
4331        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4332
4333        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4334
4335        assert_eq!(
4336            r,
4337            PartialValue::Residual(Expr::or(
4338                Expr::val(false),
4339                Expr::and(Expr::unknown("a".to_string()), Expr::val(false))
4340            ))
4341        );
4342    }
4343
4344    #[test]
4345    fn or_semantics3() {
4346        // Errors on left hand side should propagate
4347        let e = Expr::or(
4348            Expr::binary_app(BinaryOp::Add, Expr::val("hello"), Expr::val(2)),
4349            Expr::and(Expr::unknown("a".to_string()), Expr::val(false)),
4350        );
4351
4352        let es = Entities::new();
4353        let exts = Extensions::none();
4354        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4355
4356        assert!(eval.partial_interpret(&e, &HashMap::new()).is_err());
4357    }
4358
4359    #[test]
4360    fn or_semantics4() {
4361        // Left hand is residual, errors on right hand side should _not_ propagate
4362        let e = Expr::or(
4363            Expr::binary_app(BinaryOp::Eq, Expr::unknown("a".to_string()), Expr::val(2)),
4364            Expr::and(Expr::val("hello"), Expr::val("bye")),
4365        );
4366
4367        let es = Entities::new();
4368        let exts = Extensions::none();
4369        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4370
4371        assert!(eval.partial_interpret(&e, &HashMap::new()).is_ok());
4372    }
4373
4374    #[test]
4375    fn record_semantics_err() {
4376        let a = Expr::get_attr(
4377            Expr::record([("value".into(), Expr::unknown("test".to_string()))]),
4378            "notpresent".into(),
4379        );
4380
4381        let es = Entities::new();
4382        let exts = Extensions::none();
4383        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4384
4385        assert!(eval.partial_interpret(&a, &HashMap::new()).is_err());
4386    }
4387
4388    #[test]
4389    fn record_semantics_key_present() {
4390        let a = Expr::get_attr(
4391            Expr::record([("value".into(), Expr::unknown("test".to_string()))]),
4392            "value".into(),
4393        );
4394
4395        let es = Entities::new();
4396        let exts = Extensions::none();
4397        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4398
4399        let r = eval.partial_interpret(&a, &HashMap::new()).unwrap();
4400
4401        let expected = PartialValue::Residual(Expr::unknown("test"));
4402
4403        assert_eq!(r, expected);
4404    }
4405
4406    #[test]
4407    fn record_semantics_missing_attr() {
4408        let a = Expr::get_attr(
4409            Expr::record([
4410                ("a".into(), Expr::unknown("a")),
4411                ("b".into(), Expr::unknown("c")),
4412            ]),
4413            "c".into(),
4414        );
4415
4416        let es = Entities::new();
4417        let exts = Extensions::none();
4418        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4419
4420        assert!(eval.partial_interpret(&a, &HashMap::new()).is_err());
4421    }
4422
4423    #[test]
4424    fn record_semantics_mult_unknowns() {
4425        let a = Expr::get_attr(
4426            Expr::record([
4427                ("a".into(), Expr::unknown("a")),
4428                ("b".into(), Expr::unknown("b")),
4429            ]),
4430            "b".into(),
4431        );
4432
4433        let es = Entities::new();
4434        let exts = Extensions::none();
4435        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4436
4437        let r = eval.partial_interpret(&a, &HashMap::new()).unwrap();
4438
4439        let expected = PartialValue::Residual(Expr::unknown("b"));
4440
4441        assert_eq!(r, expected);
4442    }
4443
4444    #[test]
4445    fn parital_if_noerrors() {
4446        let guard = Expr::get_attr(Expr::unknown("a"), "field".into());
4447        let cons = Expr::val(1);
4448        let alt = Expr::val(2);
4449        let e = Expr::ite(guard.clone(), cons, alt);
4450
4451        let es = Entities::new();
4452        let exts = Extensions::none();
4453        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4454
4455        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4456
4457        let expected = Expr::ite(guard, Expr::val(1), Expr::val(2));
4458
4459        assert_eq!(r, PartialValue::Residual(expected));
4460    }
4461
4462    #[test]
4463    fn parital_if_cons_error() {
4464        let guard = Expr::get_attr(Expr::unknown("a"), "field".into());
4465        let cons = Expr::binary_app(BinaryOp::Add, Expr::val(1), Expr::val(true));
4466        let alt = Expr::val(2);
4467        let e = Expr::ite(guard.clone(), cons, alt);
4468
4469        let es = Entities::new();
4470        let exts = Extensions::none();
4471        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4472
4473        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4474
4475        let expected = Expr::ite(
4476            guard,
4477            Expr::call_extension_fn(
4478                "error".parse().unwrap(),
4479                vec![Expr::val("type error: expected long, got bool")],
4480            ),
4481            Expr::val(2),
4482        );
4483
4484        assert_eq!(r, PartialValue::Residual(expected));
4485    }
4486
4487    #[test]
4488    fn parital_if_alt_error() {
4489        let guard = Expr::get_attr(Expr::unknown("a"), "field".into());
4490        let cons = Expr::val(2);
4491        let alt = Expr::binary_app(BinaryOp::Add, Expr::val(1), Expr::val(true));
4492        let e = Expr::ite(guard.clone(), cons, alt);
4493
4494        let es = Entities::new();
4495        let exts = Extensions::none();
4496        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4497
4498        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4499
4500        let expected = Expr::ite(
4501            guard,
4502            Expr::val(2),
4503            Expr::call_extension_fn(
4504                "error".parse().unwrap(),
4505                vec![Expr::val("type error: expected long, got bool")],
4506            ),
4507        );
4508        assert_eq!(r, PartialValue::Residual(expected));
4509    }
4510
4511    #[test]
4512    fn parital_if_both_error() {
4513        let guard = Expr::get_attr(Expr::unknown("a"), "field".into());
4514        let cons = Expr::binary_app(BinaryOp::Add, Expr::val(1), Expr::val(true));
4515        let alt = Expr::less(Expr::val("hello"), Expr::val("bye"));
4516        let e = Expr::ite(guard, cons, alt);
4517
4518        let es = Entities::new();
4519        let exts = Extensions::none();
4520        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4521
4522        assert!(eval.partial_interpret(&e, &HashMap::new()).is_err());
4523    }
4524
4525    // err && res -> err
4526    #[test]
4527    fn partial_and_err_res() {
4528        let lhs = Expr::binary_app(BinaryOp::Add, Expr::val(1), Expr::val("test"));
4529        let rhs = Expr::get_attr(Expr::unknown("test"), "field".into());
4530        let e = Expr::and(lhs, rhs);
4531        let es = Entities::new();
4532        let exts = Extensions::none();
4533        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4534
4535        assert!(eval.partial_interpret(&e, &HashMap::new()).is_err());
4536    }
4537
4538    // err || res -> err
4539    #[test]
4540    fn partial_or_err_res() {
4541        let lhs = Expr::binary_app(BinaryOp::Add, Expr::val(1), Expr::val("test"));
4542        let rhs = Expr::get_attr(Expr::unknown("test"), "field".into());
4543        let e = Expr::or(lhs, rhs);
4544        let es = Entities::new();
4545        let exts = Extensions::none();
4546        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4547
4548        assert!(eval.partial_interpret(&e, &HashMap::new()).is_err());
4549    }
4550
4551    // true && res -> true && res
4552    #[test]
4553    fn partial_and_true_res() {
4554        let lhs = Expr::binary_app(BinaryOp::Eq, Expr::val(1), Expr::val(1));
4555        let rhs = Expr::get_attr(Expr::unknown("test"), "field".into());
4556        let e = Expr::and(lhs, rhs);
4557        let es = Entities::new();
4558        let exts = Extensions::none();
4559        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4560
4561        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4562
4563        let expected = Expr::and(
4564            Expr::val(true),
4565            Expr::get_attr(Expr::unknown("test"), "field".into()),
4566        );
4567        assert_eq!(r, PartialValue::Residual(expected));
4568    }
4569
4570    // false && res -> false
4571    #[test]
4572    fn partial_and_false_res() {
4573        let lhs = Expr::binary_app(BinaryOp::Eq, Expr::val(2), Expr::val(1));
4574        let rhs = Expr::get_attr(Expr::unknown("test"), "field".into());
4575        let e = Expr::and(lhs, rhs);
4576        let es = Entities::new();
4577        let exts = Extensions::none();
4578        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4579
4580        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4581        assert_eq!(r, PartialValue::Value(Value::Lit(false.into())));
4582    }
4583
4584    // res && true -> res && true
4585    #[test]
4586    fn partial_and_res_true() {
4587        let lhs = Expr::get_attr(Expr::unknown("test"), "field".into());
4588        let rhs = Expr::binary_app(BinaryOp::Eq, Expr::val(2), Expr::val(2));
4589        let e = Expr::and(lhs.clone(), rhs);
4590        let es = Entities::new();
4591        let exts = Extensions::none();
4592        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4593
4594        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4595        let expected = Expr::and(lhs, Expr::val(true));
4596        assert_eq!(r, PartialValue::Residual(expected));
4597    }
4598
4599    #[test]
4600    fn partial_and_res_false() {
4601        let lhs = Expr::get_attr(Expr::unknown("test"), "field".into());
4602        let rhs = Expr::binary_app(BinaryOp::Eq, Expr::val(2), Expr::val(1));
4603        let e = Expr::and(lhs.clone(), rhs);
4604        let es = Entities::new();
4605        let exts = Extensions::none();
4606        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4607
4608        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4609        let expected = Expr::and(lhs, Expr::val(false));
4610        assert_eq!(r, PartialValue::Residual(expected));
4611    }
4612
4613    // res && res -> res && res
4614    #[test]
4615    fn partial_and_res_res() {
4616        let lhs = Expr::unknown("b");
4617        let rhs = Expr::get_attr(Expr::unknown("test"), "field".into());
4618        let e = Expr::and(lhs, rhs);
4619        let es = Entities::new();
4620        let exts = Extensions::none();
4621        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4622
4623        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4624
4625        let expected = Expr::and(
4626            Expr::unknown("b"),
4627            Expr::get_attr(Expr::unknown("test"), "field".into()),
4628        );
4629        assert_eq!(r, PartialValue::Residual(expected));
4630    }
4631
4632    // res && err -> res && err
4633    #[test]
4634    fn partial_and_res_err() {
4635        let lhs = Expr::get_attr(Expr::unknown("test"), "field".into());
4636        let rhs = Expr::binary_app(BinaryOp::Add, Expr::val(1), Expr::val("oops"));
4637        let e = Expr::and(lhs, rhs);
4638        let es = Entities::new();
4639        let exts = Extensions::none();
4640        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4641
4642        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4643
4644        let expected = Expr::and(
4645            Expr::get_attr(Expr::unknown("test"), "field".into()),
4646            Expr::call_extension_fn(
4647                "error".parse().unwrap(),
4648                vec![Expr::val("type error: expected long, got string")],
4649            ),
4650        );
4651        assert_eq!(r, PartialValue::Residual(expected));
4652    }
4653
4654    // true || res -> true
4655    #[test]
4656    fn partial_or_true_res() {
4657        let lhs = Expr::binary_app(BinaryOp::Eq, Expr::val(1), Expr::val(1));
4658        let rhs = Expr::get_attr(Expr::unknown("test"), "field".into());
4659        let e = Expr::or(lhs, rhs);
4660        let es = Entities::new();
4661        let exts = Extensions::none();
4662        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4663
4664        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4665        assert_eq!(r, PartialValue::Value(Value::Lit(true.into())));
4666    }
4667
4668    // false || res -> false || res
4669    #[test]
4670    fn partial_or_false_res() {
4671        let lhs = Expr::binary_app(BinaryOp::Eq, Expr::val(2), Expr::val(1));
4672        let rhs = Expr::get_attr(Expr::unknown("test"), "field".into());
4673        let e = Expr::or(lhs, rhs);
4674        let es = Entities::new();
4675        let exts = Extensions::none();
4676        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4677
4678        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4679        let expected = Expr::or(
4680            Expr::val(false),
4681            Expr::get_attr(Expr::unknown("test"), "field".into()),
4682        );
4683        assert_eq!(r, PartialValue::Residual(expected));
4684    }
4685
4686    // res || true -> res || true
4687    #[test]
4688    fn partial_or_res_true() {
4689        let lhs = Expr::get_attr(Expr::unknown("test"), "field".into());
4690        let rhs = Expr::binary_app(BinaryOp::Eq, Expr::val(2), Expr::val(2));
4691        let e = Expr::or(lhs.clone(), rhs);
4692        let es = Entities::new();
4693        let exts = Extensions::none();
4694        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4695
4696        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4697        let expected = Expr::or(lhs, Expr::val(true));
4698        assert_eq!(r, PartialValue::Residual(expected));
4699    }
4700
4701    #[test]
4702    fn partial_or_res_false() {
4703        let lhs = Expr::get_attr(Expr::unknown("test"), "field".into());
4704        let rhs = Expr::binary_app(BinaryOp::Eq, Expr::val(2), Expr::val(1));
4705        let e = Expr::or(lhs.clone(), rhs);
4706        let es = Entities::new();
4707        let exts = Extensions::none();
4708        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4709
4710        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4711        let expected = Expr::or(lhs, Expr::val(false));
4712        assert_eq!(r, PartialValue::Residual(expected));
4713    }
4714
4715    // res || res -> res || res
4716    #[test]
4717    fn partial_or_res_res() {
4718        let lhs = Expr::unknown("b");
4719        let rhs = Expr::get_attr(Expr::unknown("test"), "field".into());
4720        let e = Expr::or(lhs, rhs);
4721        let es = Entities::new();
4722        let exts = Extensions::none();
4723        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4724
4725        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4726
4727        let expected = Expr::or(
4728            Expr::unknown("b"),
4729            Expr::get_attr(Expr::unknown("test"), "field".into()),
4730        );
4731        assert_eq!(r, PartialValue::Residual(expected));
4732    }
4733
4734    // res || err -> res || err
4735    #[test]
4736    fn partial_or_res_err() {
4737        let lhs = Expr::get_attr(Expr::unknown("test"), "field".into());
4738        let rhs = Expr::binary_app(BinaryOp::Add, Expr::val(1), Expr::val("oops"));
4739        let e = Expr::or(lhs, rhs);
4740        let es = Entities::new();
4741        let exts = Extensions::none();
4742        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4743
4744        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4745
4746        let expected = Expr::or(
4747            Expr::get_attr(Expr::unknown("test"), "field".into()),
4748            Expr::call_extension_fn(
4749                "error".parse().unwrap(),
4750                vec![Expr::val("type error: expected long, got string")],
4751            ),
4752        );
4753        assert_eq!(r, PartialValue::Residual(expected));
4754    }
4755
4756    #[test]
4757    fn partial_unop() {
4758        let es = Entities::new();
4759        let exts = Extensions::none();
4760        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4761
4762        let e = Expr::unary_app(UnaryOp::Neg, Expr::unknown("a"));
4763        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4764        assert_eq!(r, PartialValue::Residual(e));
4765
4766        let e = Expr::unary_app(UnaryOp::Not, Expr::unknown("a"));
4767        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4768        assert_eq!(r, PartialValue::Residual(e));
4769    }
4770
4771    #[test]
4772    fn partial_binop() {
4773        let es = Entities::new();
4774        let exts = Extensions::none();
4775        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4776
4777        let binops = [
4778            BinaryOp::Add,
4779            BinaryOp::Contains,
4780            BinaryOp::ContainsAll,
4781            BinaryOp::ContainsAny,
4782            BinaryOp::Eq,
4783            BinaryOp::In,
4784            BinaryOp::Less,
4785            BinaryOp::LessEq,
4786            BinaryOp::Sub,
4787        ];
4788
4789        for binop in binops {
4790            // ensure PE evaluates left side
4791            let e = Expr::binary_app(
4792                binop,
4793                Expr::binary_app(BinaryOp::Add, Expr::val(1), Expr::val(2)),
4794                Expr::unknown("a"),
4795            );
4796            let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4797            let expected = Expr::binary_app(binop, Expr::val(3), Expr::unknown("a"));
4798            assert_eq!(r, PartialValue::Residual(expected));
4799            // ensure PE propagates left side errors
4800            let e = Expr::binary_app(
4801                binop,
4802                Expr::binary_app(BinaryOp::Add, Expr::val("hello"), Expr::val(2)),
4803                Expr::unknown("a"),
4804            );
4805            assert!(eval.partial_interpret(&e, &HashMap::new()).is_err());
4806            // ensure PE evaluates right side
4807            let e = Expr::binary_app(
4808                binop,
4809                Expr::unknown("a"),
4810                Expr::binary_app(BinaryOp::Add, Expr::val(1), Expr::val(2)),
4811            );
4812            let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4813            let expected = Expr::binary_app(binop, Expr::unknown("a"), Expr::val(3));
4814            assert_eq!(r, PartialValue::Residual(expected));
4815            // ensure PE propagates right side errors
4816            let e = Expr::binary_app(
4817                binop,
4818                Expr::unknown("a"),
4819                Expr::binary_app(BinaryOp::Add, Expr::val("hello"), Expr::val(2)),
4820            );
4821            assert!(eval.partial_interpret(&e, &HashMap::new()).is_err());
4822            // Both left and right residuals
4823            let e = Expr::binary_app(binop, Expr::unknown("a"), Expr::unknown("b"));
4824            let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4825            let expected = Expr::binary_app(binop, Expr::unknown("a"), Expr::unknown("b"));
4826            assert_eq!(r, PartialValue::Residual(expected));
4827        }
4828    }
4829
4830    #[test]
4831    fn partial_mul() {
4832        let es = Entities::new();
4833        let exts = Extensions::none();
4834        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4835
4836        let e = Expr::mul(Expr::unknown("a"), 32);
4837        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4838        assert_eq!(r, PartialValue::Residual(e));
4839    }
4840
4841    #[test]
4842    fn partial_ext_constructors() {
4843        let es = Entities::new();
4844        let exts = Extensions::all_available();
4845        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4846
4847        let e = Expr::call_extension_fn("ip".parse().unwrap(), vec![Expr::unknown("a")]);
4848
4849        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4850
4851        assert_eq!(r, PartialValue::Residual(e));
4852    }
4853
4854    #[test]
4855    fn partial_ext_unfold() {
4856        let es = Entities::new();
4857        let exts = Extensions::all_available();
4858        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4859
4860        let a = Expr::call_extension_fn("ip".parse().unwrap(), vec![Expr::val("127.0.0.1")]);
4861        let b = Expr::unknown("a");
4862        let e = Expr::call_extension_fn("isInRange".parse().unwrap(), vec![a, b]);
4863
4864        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4865
4866        assert_eq!(r, PartialValue::Residual(e));
4867
4868        let b = Expr::call_extension_fn("ip".parse().unwrap(), vec![Expr::val("127.0.0.1")]);
4869        let a = Expr::unknown("a");
4870        let e = Expr::call_extension_fn("isInRange".parse().unwrap(), vec![a, b]);
4871
4872        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4873
4874        assert_eq!(r, PartialValue::Residual(e));
4875
4876        let b = Expr::call_extension_fn("ip".parse().unwrap(), vec![Expr::val("invalid")]);
4877        let a = Expr::unknown("a");
4878        let e = Expr::call_extension_fn("isInRange".parse().unwrap(), vec![a, b]);
4879
4880        assert!(eval.partial_interpret(&e, &HashMap::new()).is_err());
4881    }
4882
4883    #[test]
4884    fn partial_like() {
4885        let es = Entities::new();
4886        let exts = Extensions::none();
4887        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4888
4889        let e = Expr::like(Expr::unknown("a"), []);
4890
4891        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4892
4893        assert_eq!(r, PartialValue::Residual(e));
4894    }
4895
4896    #[test]
4897    fn partial_hasattr() {
4898        let es = Entities::new();
4899        let exts = Extensions::none();
4900        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4901
4902        let e = Expr::has_attr(Expr::unknown("a"), "test".into());
4903
4904        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4905
4906        assert_eq!(r, PartialValue::Residual(e));
4907    }
4908
4909    #[test]
4910    fn partial_set() {
4911        let es = Entities::new();
4912        let exts = Extensions::none();
4913        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4914
4915        let e = Expr::set([Expr::val(1), Expr::unknown("a"), Expr::val(2)]);
4916        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4917        assert_eq!(r, PartialValue::Residual(e));
4918
4919        let e = Expr::set([
4920            Expr::val(1),
4921            Expr::unknown("a"),
4922            Expr::binary_app(BinaryOp::Add, Expr::val(1), Expr::val(2)),
4923        ]);
4924        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4925        assert_eq!(
4926            r,
4927            PartialValue::Residual(Expr::set([Expr::val(1), Expr::unknown("a"), Expr::val(3)]))
4928        );
4929
4930        let e = Expr::set([
4931            Expr::val(1),
4932            Expr::unknown("a"),
4933            Expr::binary_app(BinaryOp::Add, Expr::val(1), Expr::val("a")),
4934        ]);
4935        assert!(eval.partial_interpret(&e, &HashMap::new()).is_err());
4936    }
4937
4938    #[test]
4939    fn partial_record() {
4940        let es = Entities::new();
4941        let exts = Extensions::none();
4942        let eval = Evaluator::new(&empty_request(), &es, &exts).unwrap();
4943
4944        let e = Expr::record([
4945            ("a".into(), Expr::val(1)),
4946            ("b".into(), Expr::unknown("a")),
4947            ("c".into(), Expr::val(2)),
4948        ]);
4949        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4950        assert_eq!(r, PartialValue::Residual(e));
4951
4952        let e = Expr::record([("a".into(), Expr::val(1)), ("a".into(), Expr::unknown("a"))]);
4953        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4954        assert_eq!(
4955            r,
4956            PartialValue::Residual(Expr::record([
4957                ("a".into(), Expr::val(1)),
4958                ("a".into(), Expr::unknown("a"))
4959            ]))
4960        );
4961
4962        let e = Expr::record([("a".into(), Expr::unknown("a")), ("a".into(), Expr::val(1))]);
4963        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4964        assert_eq!(
4965            r,
4966            PartialValue::Residual(Expr::record([
4967                ("a".into(), Expr::unknown("a")),
4968                ("a".into(), Expr::val(1))
4969            ]))
4970        );
4971
4972        let e = Expr::record([
4973            ("a".into(), Expr::val(1)),
4974            ("b".into(), Expr::unknown("a")),
4975            (
4976                "c".into(),
4977                Expr::binary_app(BinaryOp::Add, Expr::val(1), Expr::val(2)),
4978            ),
4979        ]);
4980        let r = eval.partial_interpret(&e, &HashMap::new()).unwrap();
4981        assert_eq!(
4982            r,
4983            PartialValue::Residual(Expr::record([
4984                ("a".into(), Expr::val(1)),
4985                ("b".into(), Expr::unknown("a")),
4986                ("c".into(), Expr::val(3))
4987            ]))
4988        );
4989
4990        let e = Expr::record([
4991            ("a".into(), Expr::val(1)),
4992            ("b".into(), Expr::unknown("a")),
4993            (
4994                "c".into(),
4995                Expr::binary_app(BinaryOp::Add, Expr::val(1), Expr::val("hello")),
4996            ),
4997        ]);
4998        assert!(eval.partial_interpret(&e, &HashMap::new()).is_err());
4999    }
5000
5001    #[test]
5002    fn small() {
5003        let e = parser::parse_expr("[[1]]").unwrap();
5004        let re = RestrictedExpr::new(e).unwrap();
5005        let exts = Extensions::none();
5006        let eval = RestrictedEvaluator::new(&exts);
5007        let r = eval.partial_interpret(re.as_borrowed()).unwrap();
5008        match r {
5009            PartialValue::Value(Value::Set(s)) => assert_eq!(s.len(), 1),
5010            PartialValue::Value(_) => panic!("wrong value"),
5011            PartialValue::Residual(_) => panic!("Wrong residual"),
5012        }
5013    }
5014
5015    #[test]
5016    fn unprojectable_residual() {
5017        let q = basic_request();
5018        let entities = basic_entities();
5019        let exts = Extensions::none();
5020        let eval = Evaluator::new(&q, &entities, &exts).unwrap();
5021
5022        let e = Expr::get_attr(
5023            Expr::record([
5024                (
5025                    "a".into(),
5026                    Expr::binary_app(BinaryOp::Add, Expr::unknown("a"), Expr::val(3)),
5027                ),
5028                ("b".into(), Expr::val(83)),
5029            ]),
5030            "b".into(),
5031        );
5032        let r = eval.partial_eval_expr(&e).unwrap();
5033        assert_eq!(r, Either::Right(e));
5034
5035        let e = Expr::get_attr(
5036            Expr::record([(
5037                "a".into(),
5038                Expr::binary_app(BinaryOp::Add, Expr::unknown("a"), Expr::val(3)),
5039            )]),
5040            "b".into(),
5041        );
5042        assert!(eval.partial_eval_expr(&e).is_err());
5043    }
5044}