UNPKG

@google/model-viewer

Version:

Easily display interactive 3D models on the web and in AR!

205 lines 11.2 kB
/* @license * Copyright 2019 Google LLC. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an 'AS IS' BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { expect } from 'chai'; import { CalcEvaluator, EnvEvaluator, OperatorEvaluator, PercentageEvaluator, StyleEvaluator } from '../../styles/evaluators.js'; import { numberNode } from '../../styles/parsers.js'; import { expressionNode, functionNode, identNode, operatorNode, spy } from '../helpers.js'; suite('evaluators', () => { suite('EnvEvaluator', () => { test('is never constant', () => { const evaluator = new EnvEvaluator(functionNode('env', [])); expect(evaluator.isConstant).to.be.false; }); test('with no arguments, evaluates to zero', () => { const evaluator = new EnvEvaluator(functionNode('env', [])); expect(evaluator.evaluate()).to.be.eql(numberNode(0, null)); }); suite('window-scroll-y', () => { test('evaluates to current top-level scroll position', () => { const evaluator = new EnvEvaluator(functionNode('env', [expressionNode([identNode('window-scroll-y')])])); expect(evaluator.evaluate()).to.be.eql(numberNode(0, null)); const scrollPosition = 10000; const scrollMax = 20000; const restorePageYOffset = spy(window, 'pageYOffset', { value: scrollPosition }); const restoreBodyScrollHeight = spy(document.documentElement, 'clientHeight', { value: scrollMax }); expect(evaluator.evaluate()) .to.be.eql(numberNode(scrollPosition / (scrollMax - window.innerHeight), null)); restorePageYOffset(); restoreBodyScrollHeight(); }); }); }); suite('PercentageEvaluator', () => { test('multiplies the percentage by the basis', () => { const evaluator = new PercentageEvaluator(numberNode(200, '%'), numberNode(1, 'm')); expect(evaluator.evaluate()).to.be.eql(numberNode(2, 'm')); }); }); suite('CalcEvaluator', () => { test('is constant if its operands are all numbers', () => { const evaluator = new CalcEvaluator(functionNode('calc', [expressionNode([numberNode(1, null), operatorNode('+'), numberNode(1, null)])])); expect(evaluator.isConstant).to.be.true; }); test('is constant if nested functions are constant', () => { const evaluator = new CalcEvaluator(functionNode('calc', [expressionNode([ numberNode(1, null), operatorNode('+'), functionNode('calc', [expressionNode([numberNode(1, null)])]) ])])); expect(evaluator.isConstant).to.be.true; }); test('is not constant if any nested function is not constant', () => { const evaluator = new CalcEvaluator(functionNode('calc', [ expressionNode([ numberNode(1, null), operatorNode('+'), functionNode('calc', [expressionNode([numberNode(1, null)])]), operatorNode('+'), functionNode('env', [expressionNode([identNode('window-scroll-y')])]) ]) ])); expect(evaluator.isConstant).to.be.false; }); test('with no arguments, evaluates to zero', () => { const evaluator = new CalcEvaluator(functionNode('env', [])); expect(evaluator.evaluate()).to.be.eql(numberNode(0, null)); }); test('evaluates basic addition', () => { const evaluator = new CalcEvaluator(functionNode('calc', [expressionNode([numberNode(1, null), operatorNode('+'), numberNode(1, null)])])); expect(evaluator.evaluate()).to.be.eql(numberNode(2, null)); }); test('evaluates basic subtraction', () => { const evaluator = new CalcEvaluator(functionNode('calc', [expressionNode([numberNode(1, null), operatorNode('-'), numberNode(1, null)])])); expect(evaluator.evaluate()).to.be.eql(numberNode(0, null)); }); test('evaluates basic multiplication', () => { const evaluator = new CalcEvaluator(functionNode('calc', [expressionNode([numberNode(5, null), operatorNode('*'), numberNode(4, null)])])); expect(evaluator.evaluate()).to.be.eql(numberNode(20, null)); }); test('evaluates basic division', () => { const evaluator = new CalcEvaluator(functionNode('calc', [ expressionNode([numberNode(100, null), operatorNode('/'), numberNode(10, null)]) ])); expect(evaluator.evaluate()).to.be.eql(numberNode(10, null)); }); test('evaluates complex algebraic expressions', () => { const evaluator = new CalcEvaluator(functionNode('calc', [ expressionNode([ numberNode(1, null), operatorNode('+'), numberNode(2, null), operatorNode('*'), numberNode(2.5, null), operatorNode('-'), numberNode(-2, null), operatorNode('/'), numberNode(-1, null) ]), ])); expect(evaluator.evaluate()).to.be.eql(numberNode(4, null)); }); suite('evaluates algebra with nested functions', () => { test('evaluates basic addition', () => { const evaluator = new CalcEvaluator(functionNode('calc', [expressionNode([ numberNode(1, null), operatorNode('+'), functionNode('calc', [expressionNode([numberNode(1, null)])]) ])])); expect(evaluator.evaluate()).to.be.eql(numberNode(2, null)); }); }); }); suite('OperatorEvaluator', () => { test('evaluates zero for an unknown operator', () => { const evaluator = new OperatorEvaluator(operatorNode('$'), numberNode(1, null), numberNode(1, null)); expect(evaluator.evaluate()).to.be.eql(numberNode(0, null)); }); test('evaluates zero for operands with mismatching unit types', () => { const evaluator = new OperatorEvaluator(operatorNode('+'), numberNode(1, 'm'), numberNode(1, 'rad')); expect(evaluator.evaluate()).to.be.eql(numberNode(0, null)); }); test('normalizes to base meters for length operands', () => { const evaluator = new OperatorEvaluator(operatorNode('+'), numberNode(1, 'm'), numberNode(1000, 'mm')); expect(evaluator.evaluate()).to.be.eql(numberNode(2, 'm')); }); test('normalizes to radians for angular operands', () => { const evaluator = new OperatorEvaluator(operatorNode('+'), numberNode(180, 'deg'), numberNode(Math.PI, 'rad')); expect(evaluator.evaluate()).to.be.eql(numberNode(2 * Math.PI, 'rad')); }); }); suite('VectorEvaluator', () => { suite('with SphericalIntrinsics', () => { let intrinsics; setup(() => { intrinsics = { basis: [numberNode(1, 'rad'), numberNode(1, 'rad'), numberNode(1, 'm')], keywords: { auto: [numberNode(2, 'rad'), null, numberNode(200, '%')] } }; }); test('evaluates to defaults (e.g., auto) for omitted expressions', () => { const evaluator = new StyleEvaluator([], intrinsics); expect(evaluator.evaluate()).to.be.eql([2, 1, 2]); }); test('substitutes the keyword auto for the related intrinsic value', () => { const evaluator = new StyleEvaluator([expressionNode([identNode('auto')])], intrinsics); expect(evaluator.evaluate()).to.be.eql([2, 1, 2]); }); test('treats missing values as equivalent to auto', () => { const evaluatorOne = new StyleEvaluator([expressionNode([])], intrinsics); const evaluatorTwo = new StyleEvaluator([expressionNode([identNode('auto'), identNode('auto'), identNode('auto')])], intrinsics); expect(evaluatorOne.evaluate()).to.be.eql(evaluatorTwo.evaluate()); }); test('scales the basis by an input percentage', () => { const evaluator = new StyleEvaluator([expressionNode([numberNode(300, '%')])], intrinsics); expect(evaluator.evaluate()).to.be.eql([3, 1, 2]); }); test('evaluates spherical values from basic expressions', () => { const evaluator = new StyleEvaluator([expressionNode([ numberNode(1, 'rad'), numberNode(180, 'deg'), numberNode(100, 'cm') ])], intrinsics); expect(evaluator.evaluate()).to.be.eql([1, Math.PI, 1]); }); test('applies a percentage at any expression depth to the basis', () => { const evaluator = new StyleEvaluator([expressionNode([ numberNode(150, '%'), numberNode(180, 'deg'), functionNode('calc', [expressionNode([ numberNode(200, '%'), operatorNode('*'), functionNode('calc', [expressionNode([numberNode(3, 'm')])]), ])]) ])], intrinsics); expect(evaluator.evaluate()).to.be.eql([1.5, Math.PI, 6]); }); test('evaluates spherical values from complex expressions', () => { const evaluator = new StyleEvaluator([expressionNode([ numberNode(1, 'rad'), numberNode(180, 'deg'), functionNode('calc', [expressionNode([ numberNode(1, 'm'), operatorNode('+'), functionNode('calc', [expressionNode([numberNode(1, null)])]), operatorNode('+'), functionNode('env', [expressionNode([identNode('window-scroll-y')])]) ])]) ])], intrinsics); expect(evaluator.evaluate()).to.be.eql([1, Math.PI, 2]); }); }); }); }); //# sourceMappingURL=evaluators-spec.js.map