├── .eslintrc.spec.json ├── .eslintrc.src.json ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── assets ├── UnitTestSCAD-32.png ├── UnitTestSCAD.png ├── UnitTestSCAD.xml └── banner.png ├── docs ├── Function.html ├── ThreeDModule.html ├── TwoDModule.html ├── api_AbstractModule.js.html ├── api_AbstractParent.js.html ├── api_OpenSCADFunction.js.html ├── api_ThreeDModule.js.html ├── api_TwoDModule.js.html ├── fonts │ ├── OpenSans-Bold-webfont.eot │ ├── OpenSans-Bold-webfont.svg │ ├── OpenSans-Bold-webfont.woff │ ├── OpenSans-BoldItalic-webfont.eot │ ├── OpenSans-BoldItalic-webfont.svg │ ├── OpenSans-BoldItalic-webfont.woff │ ├── OpenSans-Italic-webfont.eot │ ├── OpenSans-Italic-webfont.svg │ ├── OpenSans-Italic-webfont.woff │ ├── OpenSans-Light-webfont.eot │ ├── OpenSans-Light-webfont.svg │ ├── OpenSans-Light-webfont.woff │ ├── OpenSans-LightItalic-webfont.eot │ ├── OpenSans-LightItalic-webfont.svg │ ├── OpenSans-LightItalic-webfont.woff │ ├── OpenSans-Regular-webfont.eot │ ├── OpenSans-Regular-webfont.svg │ └── OpenSans-Regular-webfont.woff ├── global.html ├── index.html ├── index.js.html ├── scripts │ ├── linenumber.js │ └── prettify │ │ ├── Apache-License-2.0.txt │ │ ├── lang-css.js │ │ └── prettify.js ├── styles │ ├── jsdoc-default.css │ ├── prettify-jsdoc.css │ └── prettify-tomorrow.css └── types_Types.js.html ├── jsdoc.conf.json ├── llama-rlsr.config.js ├── llama-rlsr.metadata.json ├── package-lock.json ├── package.json ├── spec ├── integration │ ├── _resources │ │ └── garbage.scad │ ├── _utils │ │ └── FileUtils.js │ ├── function │ │ ├── FunctionSpec.js │ │ └── _resources │ │ │ ├── boolean.scad │ │ │ ├── inf.scad │ │ │ ├── nan.scad │ │ │ ├── number.scad │ │ │ ├── range.scad │ │ │ ├── string.scad │ │ │ ├── undef.scad │ │ │ └── vector.scad │ ├── threeD │ │ ├── ThreeDModuleSpec.js │ │ └── _resources │ │ │ ├── cube-module.scad │ │ │ └── cube.scad │ └── twoD │ │ ├── TwoDModuleSpec.js │ │ └── _resources │ │ ├── square-module.scad │ │ └── square.scad └── unit │ ├── _resources │ └── function-output.svg │ ├── api │ ├── AbstractModuleSpec.js │ ├── AbstractParentSpec.js │ ├── OpenSCADFunctionSpec.js │ ├── ThreeDModuleSpec.js │ └── TwoDModuleSpec.js │ ├── file │ ├── FileSpec.js │ ├── FunctionFileSpec.js │ ├── HeaderSpec.js │ ├── ThreeDModuleFileSpec.js │ └── TwoDModuleFileSpec.js │ ├── indexSpec.js │ └── types │ ├── TypeConverterSpec.js │ └── TypesSpec.js └── src ├── api ├── AbstractModule.js ├── AbstractParent.js ├── OpenSCADFunction.js ├── ThreeDModule.js └── TwoDModule.js ├── file ├── File.js ├── FunctionFile.js ├── Header.js ├── ThreeDModuleFile.js └── TwoDModuleFile.js ├── index.js └── types ├── TypeConverter.js └── Types.js /.eslintrc.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "node": true, 5 | "jasmine": true 6 | }, 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:jasmine/recommended" 10 | ], 11 | "parserOptions": { 12 | "ecmaVersion": 2015 13 | }, 14 | "plugins": [ 15 | "jasmine" 16 | ], 17 | "rules": { 18 | "indent": [ 19 | "error", 20 | 2 21 | ], 22 | "linebreak-style": "off", 23 | "quotes": [ 24 | "error", 25 | "single" 26 | ], 27 | "semi": [ 28 | "error", 29 | "always" 30 | ], 31 | "jasmine/no-unsafe-spy": [ 32 | "off" 33 | ], 34 | "jasmine/no-spec-dupes": [ 35 | "off" 36 | ], 37 | "jasmine/no-suite-dupes": [ 38 | "off" 39 | ], 40 | "jasmine/new-line-before-expect": [ 41 | "off" 42 | ], 43 | "jasmine/new-line-between-declarations": [ 44 | "off" 45 | ] 46 | } 47 | } -------------------------------------------------------------------------------- /.eslintrc.src.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es6": true, 4 | "node": true 5 | }, 6 | "extends": "eslint:recommended", 7 | "parserOptions": { 8 | "ecmaVersion": 2015 9 | }, 10 | "rules": { 11 | "indent": [ 12 | "error", 13 | 2 14 | ], 15 | "linebreak-style": "off", 16 | "quotes": [ 17 | "error", 18 | "single" 19 | ], 20 | "semi": [ 21 | "error", 22 | "always" 23 | ] 24 | } 25 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Desktop (please complete the following information):** 24 | - OS: [e.g. iOS] 25 | - Browser [e.g. chrome, safari] 26 | - Version [e.g. 22] 27 | 28 | **Smartphone (please complete the following information):** 29 | - Device: [e.g. iPhone6] 30 | - OS: [e.g. iOS8.1] 31 | - Browser [e.g. stock browser, safari] 32 | - Version [e.g. 22] 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Coverage directory used by tools like istanbul 12 | coverage 13 | 14 | # nyc test coverage 15 | .nyc_output 16 | 17 | # Dependency directories 18 | node_modules 19 | 20 | # Optional npm cache directory 21 | .npm 22 | 23 | # Optional REPL history 24 | .node_repl_history 25 | 26 | credentials -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 10 4 | before_install: 5 | - sudo add-apt-repository -y ppa:openscad/releases 6 | - sudo apt-get update 7 | - sudo apt-get install openscad 8 | install: 9 | - npm install 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | ## [Unreleased] 8 | - Nothing yet 9 | 10 | ## [3.0.3] 2018-09-27 11 | ### Fixed 12 | - Fixed `main` entry in `package.json` to point to UnitTestSCAD's correct entry point. 13 | 14 | ## [3.0.2] 2018-09-20 15 | ### Fixed 16 | - Moved `jsdoc` from `dependencies` to `devDependencies`. 17 | 18 | ## [3.0.1] 2018-09-20 19 | ### Fixed 20 | - Fixed `package-lock.json`. 21 | 22 | ## [3.0.0] 2018-09-17 23 | ### Changed 24 | - Entire API has been reworked. 25 | - Removed all assertion methods. 26 | - Removed test runner, test suite handling and associated reporting capabilities. 27 | - UnitTestSCAD now exposes `Function`, `ThreeDModule`, `TwoDModule` and `Types`. This should be used in conjunction with other testing frameworks to build up test suites. 28 | - Changed documentation from markdown to JSDoc. This can be found at [docs/index.html](docs/index.html). 29 | 30 | ## [2.2.0] 2017-07-29 31 | ### Added 32 | - Added `toContainVertices` and `toHaveExactVertices`. 33 | 34 | ### Changes 35 | - Arrays/Vectors now print nicer to console. 36 | 37 | ## [2.1.1] 2017-07-27 38 | ### Fixed 39 | - Finding vertices also works on floats. 40 | - Minor internal improvements. 41 | 42 | ## [2.1.0] 2017-07-16 43 | ### Added 44 | - `typeToBe` assertion added to `openScadFunction` tests. 45 | 46 | ## [2.0.1] 2017-06-28 47 | ### Added 48 | - Can now invoke `unittestscad` through NodeJS `require`. 49 | 50 | ### Fixed 51 | - Exceptions from user specs now correctly bubble up. 52 | 53 | ## [2.0.0] 2017-06-08 54 | ### Added 55 | - `assert` now has an optional `withSetup(setupText)` to allow insertion of OpenSCAD code, prior to the test. Chains with both `openScadFunction()` and `openScadModule()`. 56 | - `assert.openScad2DModule()` now available, along with assertions for 2D modules. 57 | - `xml` reporter now available. 58 | 59 | ### Changed 60 | - Now allow for trailing semi-colons in assertion definitions. 61 | - `assert.openScad3DModule()` available as an alias to `assert.openScadModule()`. 62 | 63 | ## [1.2.1] 2017-07-23 64 | ### Fixed 65 | - Finding vertices also works on floats. 66 | 67 | ## [1.2.0] 2017-06-01 68 | ### Added 69 | - Added reporters, and ability to add custom reporters. 70 | 71 | ### Fixed 72 | - `openScadFunction().outputToBe('...')` now performs a strict equality check, rather than weak containment check. 73 | 74 | ## [1.1.0] 2017-05-28 75 | ### Added 76 | - `not()` function to both `openScadFunction()` and `openScadModule`. Inverts the expectation of the next chained assertion. 77 | 78 | ## [1.0.1] 2017-05-09 79 | ### Fixed 80 | - Clean up of temporary files should be consistent after each run. 81 | 82 | ## [1.0.0] 2017-05-07 83 | ### Added 84 | - Initial release hype! 85 | 86 | [Unreleased]: https://github.com/HopefulLlama/UnitTestSCAD/compare/v3.0.3...HEAD 87 | [3.0.3]: https://github.com/HopefulLlama/UnitTestSCAD/compare/v3.0.2...v3.0.3 88 | [3.0.2]: https://github.com/HopefulLlama/UnitTestSCAD/compare/v3.0.1...v3.0.2 89 | [3.0.1]: https://github.com/HopefulLlama/UnitTestSCAD/compare/v3.0.0...v3.0.1 90 | [3.0.0]: https://github.com/HopefulLlama/UnitTestSCAD/compare/v2.2.0...v3.0.0 91 | [2.2.0]: https://github.com/HopefulLlama/UnitTestSCAD/compare/v2.1.1...v2.2.0 92 | [2.1.1]: https://github.com/HopefulLlama/UnitTestSCAD/compare/v2.1.0...v2.1.1 93 | [2.1.0]: https://github.com/HopefulLlama/UnitTestSCAD/compare/v2.0.1...v2.1.0 94 | [2.0.1]: https://github.com/HopefulLlama/UnitTestSCAD/compare/v2.0.0...v2.0.1 95 | [2.0.0]: https://github.com/HopefulLlama/UnitTestSCAD/compare/v1.2.0...v2.0.0 96 | [1.2.1]: https://github.com/HopefulLlama/UnitTestSCAD/compare/v1.2.0...v1.2.1 97 | [1.2.0]: https://github.com/HopefulLlama/UnitTestSCAD/compare/v1.1.0...v1.2.0 98 | [1.1.0]: https://github.com/HopefulLlama/UnitTestSCAD/compare/v1.0.1...v1.1.0 99 | [1.0.1]: https://github.com/HopefulLlama/UnitTestSCAD/compare/v1.0.0...v1.0.1 100 | [1.0.0]: https://github.com/HopefulLlama/UnitTestSCAD/compare/15ab1edb7d358de72afc3d664f776a2cf1e7e720...v1.0.0 101 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are welcome. Very very welcome. 4 | 5 | ## Issues Page 6 | 7 | The [GitHub Issues](https://github.com/HopefulLlama/UnitTestSCAD/issues) page for UnitTestSCAD covers a variety of things: 8 | - Bugs 9 | - Features 10 | - Discussions 11 | - To do items 12 | 13 | Please feel free to join in! 14 | 15 | ### Bugs 16 | Include as much detail as possible. 17 | - What were you trying to do? 18 | - What happened instead? 19 | - What did you do to make it happen? 20 | 21 | ### Feature Requests 22 | Include as much detail as possible. 23 | - What would this new feature do? What problem does it fix? 24 | - Is this achievable by the current implementation of JointSCAD at all? 25 | 26 | ### Discussions 27 | Feel free to add your input to any item within the [GitHub Issues](https://github.com/HopefulLlama/UnitTestSCAD/issues) list. 28 | 29 | Unwritten rules apply of be nice, be open-minded, etc. 30 | 31 | ## Submitting Code 32 | GitHub has a pretty strictly enforced branch/pull request flow if you wish to submit code. See [Dev Setup](#dev-setup) about coding. 33 | 34 | ## Dev Setup 35 | Follow the instructions listed in [Getting Started](../../..#getting-started). 36 | 37 | Clone the UnitTestSCAD repository and run `npm install` to install all dependencies. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Jonathan Law 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ![UnitTestSCAD Logo](assets/UnitTestSCAD-32.png)UnitTestSCAD 2 | 3 | ![License](https://img.shields.io/npm/l/unittestscad.svg) [![NPM](https://img.shields.io/npm/v/unittestscad.svg)](https://www.npmjs.com/package/unittestscad) [![Code Climate](https://img.shields.io/codeclimate/github/HopefulLlama/UnitTestSCAD.svg)](https://codeclimate.com/github/HopefulLlama/UnitTestSCAD) [![Join the chat at https://gitter.im/UnitTestSCAD/Lobby](https://badges.gitter.im/UnitTestSCAD/Lobby.svg)](https://gitter.im/UnitTestSCAD/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 4 | 5 | ![UnitTestSCAD: expect(cube.scad).toBe(cube);](assets/banner.png) 6 | 7 | # Unit Testing for OpenSCAD 8 | 9 | UnitTestSCAD brings forth unit testing capabilities to OpenSCAD. Unit testing enables you to check for regressions, accuracy and robustness of code in a fast, repeatable manner. Speed of development increases as unit tests will worry about your regressions, and allow you to plow ahead with your vision. 10 | 11 | # Contents 12 | - [Getting Started](#getting-started) 13 | - [Usage](#usage) 14 | - [API Reference](#api-reference) 15 | 16 | # Getting Started 17 | ## Installing OpenSCAD 18 | UnitTestSCAD has a very strong dependency on OpenSCAD. This is because UnitTestSCAD uses some of the features from OpenSCAD to perform some of its underlying testing. 19 | 20 | Simply start by installing OpenSCAD if you have not done so already: 21 | 22 | [OpenSCAD Home](http://www.openscad.org/) 23 | 24 | ## Adding OpenSCAD to PATH 25 | In order for UnitTestSCAD to take advantage of OpenSCAD's features, the folder which contains the OpenSCAD files must be added to the PATH environment variable on your machine. 26 | 27 | While the path will generally be the same on all platforms (Windows, Linux, Mac), the file they point to specifically is different. If you have moved the respective file manually, you will need to point at: 28 | - Windows: `openscad.com` 29 | - Linux: `openscad.exe` 30 | - Mac: `openscad.exe` 31 | 32 | These files will be in the location where you installed OpenSCAD. For example, by default on Windows: `C:/Program Files/OpenSCAD`. 33 | 34 | Note: **The path to the folder containing the files is to be added to the PATH environment variable.** 35 | 36 | ## Installing NodeJS and NPM 37 | UnitTestSCAD is powered by NodeJS and distributed by NPM. They are distributed together and complement each other well. 38 | Follow the installation from the NodeJS website if you do not have these installed: 39 | 40 | [NodeJS Home](https://nodejs.org/en/) 41 | 42 | ## Installing UnitTestSCAD 43 | If all has gone well, then installing UnitTestSCAD will be a simple command to run in the command line/terminal. 44 | 45 | To install UnitTestSCAD, run the command: 46 | 47 | `npm i unittestscad` 48 | 49 | # Usage 50 | UnitTestSCAD should be required as standard into a NodeJS script. 51 | 52 | ```javascript 53 | const UnitTestSCAD = require('unittestscad'); 54 | ``` 55 | 56 | `UnitTestSCAD` exposes several classes designed at enabling assertions on your `.scad` functions and modules. For example, to assert against a `.scad` file which produces a cube (`cube.scad`), you can create it as such: 57 | 58 | ```javascript 59 | const cube = new UnitTestSCAD.ThreeDModule({ 60 | include: 'cube.scad' 61 | }); 62 | 63 | cube.height === 5; 64 | ``` 65 | 66 | # API Reference 67 | See [API Documentation](https://hopefulllama.github.io/UnitTestSCAD/) for more details. -------------------------------------------------------------------------------- /assets/UnitTestSCAD-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HopefulLlama/UnitTestSCAD/ad8ac537c99dfc7f10d46839db2910f9b940e946/assets/UnitTestSCAD-32.png -------------------------------------------------------------------------------- /assets/UnitTestSCAD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HopefulLlama/UnitTestSCAD/ad8ac537c99dfc7f10d46839db2910f9b940e946/assets/UnitTestSCAD.png -------------------------------------------------------------------------------- /assets/UnitTestSCAD.xml: -------------------------------------------------------------------------------- 1 | 5VfJkqNIEv2aNJs5jBn7cmQRCIQEAoFAN5ZA7CB2+PoJKqWqzK6q7q7psTEba10E7s8j3J+/cCnecKGc5dZvkmMdgeINQ6L5DRffMAxFCQx+bZbl3UKyyLvh3qbRE/TNYKUreBpfsCGNQPcJ2Nd10afNZ2NYVxUI+082v23r6TMsrovPuzb+HXxnsEK/+N56TaM+eWWHfLPvQXpP+t84Aj/M7209VM/t3jA8/vJ5d5f+a6knvkv8qJ4+mPDdGy60dd2/P5WzAIqN2hdr73HST7xf025B1f+ZAOKZx+gXA3il/CWxfnlxsdXTPGGg7cH8ow74wQuOfJ8D+rUyKBhQl6BvFwh5LvQv6hmy/OZ9+sD8a9nkI+svo//s9v3r2t9Khg/Pqn/MwKuO32MAdqnZHrseVGFa/KO/XaKgPk6ico2TfEjPJ/Ph7sgOTG8Y7w6J4KhppgoVTstntbURwVfTOlFV6L3EmhxVSJb3tSLXpOnmcaog2SWpDMLuEWbGOE8jGbuVuXIvt2hWRVIV6K6ZnZfmkF0s1qeJzLjTGchhabkZ+QdPVdrrejeM+46jilobGCaQVriZlJ9PjAVhNaLMqji0Lk4WHTupD6ZujmeI8G2W9m8BxIUICrrCCGz1BAOOuaMvfZ1IY86n1alhtZBaIbcAtiQ87on+6kQwfBowp+QgRVKABfLtxCIOYByS7q9mbWtrpjlthx9Dzo6YbTcP20Movx/Xziz2tHgPVuJAGlaHlryacZ1fyV17J073a3erNPe8RL22N8XxURp4q4mWxDZWjGAphoXNfcWIhGdDuGCmGBP3zzecn5K0B1bjh1uzJjiZoC3pS9h6EYWPXd/WORDqom6/9BWXpN0OntyX53XS0c30U8F/FDaB/FjZ/xvlYn9Vuf1ZOShOMZ8CnNELLbcKwT0s556FveJCzZdUoUztWjmAeOdia7UJWCDbh8grsuRMcANeVJX81uEMHcDUJLnmu24VMnDnzqE/T1FgJ1HH2xUxw0ORZwIr0BAm9Om+ijadGbBK3i54Ly1OFmDgixnIXNJ4aI5P/bpEGx321SAc8aZqYcEZMRbJlDnUzKVb2Ftxwfu+HJK9s64OjF4Qsj8TOAxagEU6kacfoUJ4w5bmg91v5pPC+mxIHb6o2HaibI66NuRkiKqgVpeAfpQ08divRt2ibqz6lJhuolWn25mx+XxgshFfqIDfqxc78ckJEXGHsuVDJiOzwYebzstof0LSU6WTArW76KlZ1Dpcg+roONz5w3g62hAVEQO7l9VSX+WagO6OEEQG9upvqGT8P1Jy8K5k/13J+kC5Nol8mMGFbElxix2nyzVsDqVgWTvS2NQwrpmuAKHRbD7LNS4llPBuXTWZ2rHzyWt5v1tCCWPvPD9rrEKiZoFNuzR2j965Q7jMHYxp9XgGacaCKNO8ESwoLs6oFiv0hF1JtoY/BWNLKydtN1KqiMzu7VHAUyXdEJ8W/WyWGlsvXTyiUJ/aVY7n06t6eaBiBv8oSCop5I1FAK9BYkVrC3PTs4KsTouscD5mhtSmtIZI2NzczYcP1nAG4/AIxsSD1YVDXeHdlTZBgC4Gd+MY4YL4CsvG9XoeSplWM9sNr+se6wqZX0Ql96p8VPgp3jt1Qh36MEGPB9nMiroc6W69gB2rXAEidzjG1NiNVswWPOIZDQjuvPXmFxT7SZc/F/H/gWKJ/8Ls1UdJSwE2epHmeslhB5tn5UlAs6JioQeLP+1I+2x3lDqymX5ZzPWKyKJt+Q9rT8rXm3eYXAb0CJt1HHINEms8cy128ig9upo6dniIzLQUh+VSgGL7sTbBQSRhYVa8ckN2snUbudymfbXI90gJD3RtkjBfOOp8fZuG1wixRFo9x1B9vL4at9ET/DHVLrlYFeMVK2V0L7on3aVPZww1rPiilmtX+cotoPZEYVkDyERDbh19bgUeGK5T2azbCiiXjDXN4sdSX9YBHFhmmNjc3s8BTfPW9qdC5ZxLKFwUdVjA6nujsrKpOvOMNGRIe3IE9Xg2Mm9Ci1Amu5TNjqRFyZe+9DIFjlme3IYpCDPWc7FcNXBfq8w5vY3d9NCNVufu0P03nLH0HysWRsALFvhjbvyueb91xekMol8lK06L4gWt6gr8Vf6eEfjnawT+/S2C+gG51K9zC1+/3dC++D7cgvHdvwE= -------------------------------------------------------------------------------- /assets/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HopefulLlama/UnitTestSCAD/ad8ac537c99dfc7f10d46839db2910f9b940e946/assets/banner.png -------------------------------------------------------------------------------- /docs/Function.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Class: Function 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Class: Function

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 |
30 | 31 |

Function(options)

32 | 33 | 34 |
35 | 36 |
37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 |

new Function(options)

45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
Parameters:
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 |
NameTypeDescription
options 88 | 89 | 90 | Options 91 | 92 | 93 | 94 |
106 | 107 | 108 | 109 | 110 | 111 | 112 |
113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 |
Source:
140 |
143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 |
151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 |
171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 |

Members

186 | 187 | 188 | 189 |

output :string

190 | 191 | 192 | 193 | 194 |
195 | The extracted output from execution of the .scad file. 196 |
197 | 198 | 199 | 200 |
Type:
201 |
    202 |
  • 203 | 204 | string 205 | 206 | 207 |
  • 208 |
209 | 210 | 211 | 212 | 213 | 214 |
215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 |
Source:
242 |
245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 |
253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 |

type :Type

262 | 263 | 264 | 265 | 266 |
267 | The detected type of the value retrieved from the OpenSCAD function. 268 |
269 | 270 | 271 | 272 |
Type:
273 |
    274 |
  • 275 | 276 | Type 277 | 278 | 279 |
  • 280 |
281 | 282 | 283 | 284 | 285 | 286 |
287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 |
Source:
314 |
317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 |
325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 |

Methods

336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 |

isBoolean() → {boolean}

344 | 345 | 346 | 347 | 348 | 349 | 350 |
351 | Returns true if this type is of type OpenSCADBoolean. 352 |
353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 |
367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 |
Source:
394 |
397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 |
405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 |
Returns:
419 | 420 | 421 |
422 | True if this type is of type OpenSCADBoolean. 423 |
424 | 425 | 426 | 427 |
428 |
429 | Type 430 |
431 |
432 | 433 | boolean 434 | 435 | 436 |
437 |
438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 |

isInf() → {boolean}

452 | 453 | 454 | 455 | 456 | 457 | 458 |
459 | Returns true if this type is of type OpenSCADInfinity. 460 |
461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 |
475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 |
Source:
502 |
505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 |
513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 |
Returns:
527 | 528 | 529 |
530 | True if this type is of type OpenSCADInfinity. 531 |
532 | 533 | 534 | 535 |
536 |
537 | Type 538 |
539 |
540 | 541 | boolean 542 | 543 | 544 |
545 |
546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 |

isNan() → {boolean}

560 | 561 | 562 | 563 | 564 | 565 | 566 |
567 | Returns true if this type is of type OpenSCADNaN. 568 |
569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 |
583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 |
Source:
610 |
613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 |
621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 |
Returns:
635 | 636 | 637 |
638 | True if this type is of type OpenSCADNaN. 639 |
640 | 641 | 642 | 643 |
644 |
645 | Type 646 |
647 |
648 | 649 | boolean 650 | 651 | 652 |
653 |
654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 |

isNumber() → {boolean}

668 | 669 | 670 | 671 | 672 | 673 | 674 |
675 | Returns true if this type is of type OpenSCADNumber. 676 |
677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 |
691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 |
Source:
718 |
721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 |
729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 |
Returns:
743 | 744 | 745 |
746 | True if this type is of type OpenSCADNumber. 747 |
748 | 749 | 750 | 751 |
752 |
753 | Type 754 |
755 |
756 | 757 | boolean 758 | 759 | 760 |
761 |
762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 |

isRange() → {boolean}

776 | 777 | 778 | 779 | 780 | 781 | 782 |
783 | Returns true if this type is of type OpenSCADRange. 784 |
785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 |
799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 |
Source:
826 |
829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 |
837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 |
Returns:
851 | 852 | 853 |
854 | True if this type is of type OpenSCADBoolean. 855 |
856 | 857 | 858 | 859 |
860 |
861 | Type 862 |
863 |
864 | 865 | boolean 866 | 867 | 868 |
869 |
870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 |

isString() → {boolean}

884 | 885 | 886 | 887 | 888 | 889 | 890 |
891 | Returns true if this type is of type OpenSCADString. 892 |
893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 |
907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 | 932 | 933 |
Source:
934 |
937 | 938 | 939 | 940 | 941 | 942 | 943 | 944 |
945 | 946 | 947 | 948 | 949 | 950 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 |
Returns:
959 | 960 | 961 |
962 | True if this type is of type OpenSCADString. 963 |
964 | 965 | 966 | 967 |
968 |
969 | Type 970 |
971 |
972 | 973 | boolean 974 | 975 | 976 |
977 |
978 | 979 | 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 989 | 990 | 991 |

isUndef() → {boolean}

992 | 993 | 994 | 995 | 996 | 997 | 998 |
999 | Returns true if this type is of type OpenSCADUndefined. 1000 |
1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | 1014 |
1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1025 | 1026 | 1027 | 1028 | 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 |
Source:
1042 |
1045 | 1046 | 1047 | 1048 | 1049 | 1050 | 1051 | 1052 |
1053 | 1054 | 1055 | 1056 | 1057 | 1058 | 1059 | 1060 | 1061 | 1062 | 1063 | 1064 | 1065 | 1066 |
Returns:
1067 | 1068 | 1069 |
1070 | True if this type is of type OpenSCADUndefined. 1071 |
1072 | 1073 | 1074 | 1075 |
1076 |
1077 | Type 1078 |
1079 |
1080 | 1081 | boolean 1082 | 1083 | 1084 |
1085 |
1086 | 1087 | 1088 | 1089 | 1090 | 1091 | 1092 | 1093 | 1094 | 1095 | 1096 | 1097 | 1098 | 1099 |

isVector() → {boolean}

1100 | 1101 | 1102 | 1103 | 1104 | 1105 | 1106 |
1107 | Returns true if this type is of type OpenSCADVector. 1108 |
1109 | 1110 | 1111 | 1112 | 1113 | 1114 | 1115 | 1116 | 1117 | 1118 | 1119 | 1120 | 1121 | 1122 |
1123 | 1124 | 1125 | 1126 | 1127 | 1128 | 1129 | 1130 | 1131 | 1132 | 1133 | 1134 | 1135 | 1136 | 1137 | 1138 | 1139 | 1140 | 1141 | 1142 | 1143 | 1144 | 1145 | 1146 | 1147 | 1148 | 1149 |
Source:
1150 |
1153 | 1154 | 1155 | 1156 | 1157 | 1158 | 1159 | 1160 |
1161 | 1162 | 1163 | 1164 | 1165 | 1166 | 1167 | 1168 | 1169 | 1170 | 1171 | 1172 | 1173 | 1174 |
Returns:
1175 | 1176 | 1177 |
1178 | True if this type is of type OpenSCADVector. 1179 |
1180 | 1181 | 1182 | 1183 |
1184 |
1185 | Type 1186 |
1187 |
1188 | 1189 | boolean 1190 | 1191 | 1192 |
1193 |
1194 | 1195 | 1196 | 1197 | 1198 | 1199 | 1200 | 1201 | 1202 | 1203 | 1204 | 1205 | 1206 | 1207 |
1208 | 1209 |
1210 | 1211 | 1212 | 1213 | 1214 |
1215 | 1216 | 1219 | 1220 |
1221 | 1222 | 1225 | 1226 | 1227 | 1228 | 1229 | -------------------------------------------------------------------------------- /docs/ThreeDModule.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Class: ThreeDModule 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Class: ThreeDModule

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 |
30 | 31 |

ThreeDModule(options)

32 | 33 | 34 |
35 | 36 |
37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 |

new ThreeDModule(options)

45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
Parameters:
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 |
NameTypeDescription
options 88 | 89 | 90 | Options 91 | 92 | 93 | 94 |
106 | 107 | 108 | 109 | 110 | 111 | 112 |
113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 |
Source:
140 |
143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 |
151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 |
171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 |

Members

186 | 187 | 188 | 189 |

depth :number

190 | 191 | 192 | 193 | 194 |
195 | The depth of the model. 196 |
197 | 198 | 199 | 200 |
Type:
201 |
    202 |
  • 203 | 204 | number 205 | 206 | 207 |
  • 208 |
209 | 210 | 211 | 212 | 213 | 214 |
215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 |
Source:
242 |
245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 |
253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 |

height :number

262 | 263 | 264 | 265 | 266 |
267 | The height of the model. 268 |
269 | 270 | 271 | 272 |
Type:
273 |
    274 |
  • 275 | 276 | number 277 | 278 | 279 |
  • 280 |
281 | 282 | 283 | 284 | 285 | 286 |
287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 |
Source:
314 |
317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 |
325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 |

output :string

334 | 335 | 336 | 337 | 338 |
339 | The extracted output from execution of the .scad file. 340 |
341 | 342 | 343 | 344 |
Type:
345 |
    346 |
  • 347 | 348 | string 349 | 350 | 351 |
  • 352 |
353 | 354 | 355 | 356 | 357 | 358 |
359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 |
Source:
386 |
389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 |
397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 |

triangles :Array.<Triangle>

406 | 407 | 408 | 409 | 410 |
411 | The triangles which make up the model. See https://en.wikipedia.org/wiki/Triangle_mesh. 412 |
413 | 414 | 415 | 416 |
Type:
417 |
    418 |
  • 419 | 420 | Array.<Triangle> 421 | 422 | 423 |
  • 424 |
425 | 426 | 427 | 428 | 429 | 430 |
431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 |
Source:
458 |
461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 |
469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 |

vertices :Array.<Vertex>

478 | 479 | 480 | 481 | 482 |
483 | A list of 3D vertices returned from the .scad file execution. 484 |
485 | 486 | 487 | 488 |
Type:
489 |
    490 |
  • 491 | 492 | Array.<Vertex> 493 | 494 | 495 |
  • 496 |
497 | 498 | 499 | 500 | 501 | 502 |
503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 |
Source:
530 |
533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 |
541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 |

width :number

550 | 551 | 552 | 553 | 554 |
555 | The width of the model. 556 |
557 | 558 | 559 | 560 |
Type:
561 |
    562 |
  • 563 | 564 | number 565 | 566 | 567 |
  • 568 |
569 | 570 | 571 | 572 | 573 | 574 |
575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 |
Source:
602 |
605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 |
613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 |

Methods

624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 |

isWithinBoundingBox(boundingBox) → {boolean}

632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 |
Parameters:
647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 |
NameTypeDescription
boundingBox 675 | 676 | 677 | BoundingBox 678 | 679 | 680 | 681 | The 3D box which the model should fit inside. It is considered 'within' if any coordinate is equal to, or within the box.
693 | 694 | 695 | 696 | 697 | 698 | 699 |
700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 |
Source:
727 |
730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 |
738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 |
Returns:
752 | 753 | 754 |
755 | True if the model fits within the bounding box. 756 |
757 | 758 | 759 | 760 |
761 |
762 | Type 763 |
764 |
765 | 766 | boolean 767 | 768 | 769 |
770 |
771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 |
785 | 786 |
787 | 788 | 789 | 790 | 791 |
792 | 793 | 796 | 797 |
798 | 799 | 802 | 803 | 804 | 805 | 806 | -------------------------------------------------------------------------------- /docs/TwoDModule.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Class: TwoDModule 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Class: TwoDModule

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 |
30 | 31 |

TwoDModule(options)

32 | 33 | 34 |
35 | 36 |
37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 |

new TwoDModule(options)

45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
Parameters:
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 |
NameTypeDescription
options 88 | 89 | 90 | Options 91 | 92 | 93 | 94 |
106 | 107 | 108 | 109 | 110 | 111 | 112 |
113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 |
Source:
140 |
143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 |
151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 |
171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 |

Members

186 | 187 | 188 | 189 |

height :number

190 | 191 | 192 | 193 | 194 |
195 | The height of the model. 196 |
197 | 198 | 199 | 200 |
Type:
201 |
    202 |
  • 203 | 204 | number 205 | 206 | 207 |
  • 208 |
209 | 210 | 211 | 212 | 213 | 214 |
215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 |
Source:
242 |
245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 |
253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 |

output :string

262 | 263 | 264 | 265 | 266 |
267 | The extracted output from execution of the .scad file. 268 |
269 | 270 | 271 | 272 |
Type:
273 |
    274 |
  • 275 | 276 | string 277 | 278 | 279 |
  • 280 |
281 | 282 | 283 | 284 | 285 | 286 |
287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 |
Source:
314 |
317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 |
325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 |

vertices :Array.<Vertex>

334 | 335 | 336 | 337 | 338 |
339 | A list of 2D vertices returned from the .scad file execution. 340 |
341 | 342 | 343 | 344 |
Type:
345 |
    346 |
  • 347 | 348 | Array.<Vertex> 349 | 350 | 351 |
  • 352 |
353 | 354 | 355 | 356 | 357 | 358 |
359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 |
Source:
386 |
389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 |
397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 |

width :number

406 | 407 | 408 | 409 | 410 |
411 | The width of the model. 412 |
413 | 414 | 415 | 416 |
Type:
417 |
    418 |
  • 419 | 420 | number 421 | 422 | 423 |
  • 424 |
425 | 426 | 427 | 428 | 429 | 430 |
431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 |
Source:
458 |
461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 |
469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 |

Methods

480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 |

isWithinBoundingBox(boundingBox) → {boolean}

488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 |
Parameters:
503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 |
NameTypeDescription
boundingBox 531 | 532 | 533 | BoundingBox 534 | 535 | 536 | 537 | The 2D box which the model should fit inside. It is considered 'within' if any coordinate is equal to, or within the box.
549 | 550 | 551 | 552 | 553 | 554 | 555 |
556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 |
Source:
583 |
586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 |
594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 |
Returns:
608 | 609 | 610 |
611 | True if the model fits within the bounding box. 612 |
613 | 614 | 615 | 616 |
617 |
618 | Type 619 |
620 |
621 | 622 | boolean 623 | 624 | 625 |
626 |
627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 |
641 | 642 |
643 | 644 | 645 | 646 | 647 |
648 | 649 | 652 | 653 |
654 | 655 | 658 | 659 | 660 | 661 | 662 | -------------------------------------------------------------------------------- /docs/api_AbstractModule.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: api/AbstractModule.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: api/AbstractModule.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
const AbstractParent = require('./AbstractParent');
30 | 
31 | function isCoordinateWithinBounds(coordinate, min, max) {
32 |   return coordinate >= min && coordinate <= max;
33 | }
34 | 
35 | module.exports = class extends AbstractParent {
36 |   constructor(options, file) {
37 |     super(options, file);
38 |   }
39 | 
40 |   /**
41 |    * @typedef {object} BoundingBox A box in 2D/3D space.
42 |    * @property {Vertex} min A 2D/3D vertex which defines the 'minimum' co-ordinates. This is the corner of the box with the lowest x, y and optional z co-ordinate.
43 |    * @property {Vertex} max A 2D/3D vertex which defines the 'maximum' co-ordinates. This is the corner of the box with the highest x, y and optional z co-ordinate.
44 |    */
45 | 
46 |   isWithinBoundingBox(boundingBox) {
47 |     const failingVertices = this.vertices.reduce((failingCounter, vertex) => {
48 |       return failingCounter + vertex.reduce((accumulator, coordinate, index) => {
49 |         return isCoordinateWithinBounds(coordinate, boundingBox.min[index], boundingBox.max[index]) ? accumulator : accumulator + 1;
50 |       }, 0);
51 |     }, 0);
52 | 
53 |     return failingVertices === 0;
54 |   }
55 | };
56 |
57 |
58 | 59 | 60 | 61 | 62 |
63 | 64 | 67 | 68 |
69 | 70 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /docs/api_AbstractParent.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: api/AbstractParent.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: api/AbstractParent.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
const {getHeader} = require('../file/Header');
30 | 
31 | function valueOrDefault(object, property, defaultValue) {
32 |   return (object !== undefined && object[property] !== undefined) ? object[property] : defaultValue;
33 | }
34 | 
35 | function sanitise(options) {
36 |   return {
37 |     openSCADDirectory: valueOrDefault(options, 'openSCADDirectory', ''),
38 |     use: valueOrDefault(options, 'use', []),
39 |     include: valueOrDefault(options, 'include', []),
40 |     setUpText: valueOrDefault(options, 'setUpText', ''),
41 |     testText: valueOrDefault(options, 'testText', ''),
42 |   };
43 | }
44 | 
45 | /**
46 |  * @typedef {object} Options Key/value pair of options to configure the execution of an OpenSCAD test.
47 |  * @property {String} openSCADDirectory The prefix to prepend to all uses/includes.
48 |  * @property {String[]} use List of .scad files to import as 'use'.
49 |  * @property {String[]} include List of .scad files to import as 'include'.
50 |  * @property {String} setUpText Any required OpenSCAD code to set up the test.
51 |  * @property {String} testText The OpenSCAD code to be tested and asserted on.
52 |  */
53 | 
54 | /**
55 |  * @typedef {number[]} Vertex A 2/3 length co-ordinate representing a point in 2D/3D space.
56 |  */
57 | 
58 | module.exports = class {
59 |   constructor(dirtyOptions, fileType) {
60 |     const options = sanitise(dirtyOptions);
61 |     const header = getHeader(options.openSCADDirectory, options.use, options.include);
62 |     this.output = fileType.execute(header, options.setUpText, options.testText);
63 |   }
64 | };
65 |
66 |
67 | 68 | 69 | 70 | 71 |
72 | 73 | 76 | 77 |
78 | 79 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /docs/api_OpenSCADFunction.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: api/OpenSCADFunction.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: api/OpenSCADFunction.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
const AbstractParent = require('./AbstractParent');
 30 | const FunctionFile = require('../file/FunctionFile');
 31 | const TypeConverter = require('../types/TypeConverter');
 32 | const Types = require('../types/Types');
 33 | 
 34 | /** @class */
 35 | class Function extends AbstractParent {
 36 |   /**
 37 |    * @param {Options} options
 38 |    */
 39 |   constructor(options) {
 40 |     super(options, FunctionFile);
 41 |     /**
 42 |      * @memberof Function
 43 |      * @instance
 44 |      * @member {string} output The extracted output from execution of the .scad file.
 45 |      */
 46 |     /**
 47 |      * @memberof Function
 48 |      * @instance
 49 |      * @member {Type} type The detected type of the value retrieved from the OpenSCAD function.
 50 |      */
 51 |     this.type = TypeConverter.getType(this.output);
 52 |   }
 53 | 
 54 |   /**
 55 |    * Returns true if this type is of type {@link OpenSCADBoolean}.
 56 |    * @returns {boolean} True if this type is of type {@link OpenSCADBoolean}.
 57 |    */
 58 |   isBoolean() {
 59 |     return this.type === Types.BOOLEAN;
 60 |   }
 61 | 
 62 |   /**
 63 |    * Returns true if this type is of type {@link OpenSCADInfinity}.
 64 |    * @returns {boolean} True if this type is of type {@link OpenSCADInfinity}.
 65 |    */
 66 |   isInf() {
 67 |     return this.type === Types.INF;
 68 |   }
 69 | 
 70 |   /**
 71 |    * Returns true if this type is of type {@link OpenSCADNaN}.
 72 |    * @returns {boolean} True if this type is of type {@link OpenSCADNaN}.
 73 |    */
 74 |   isNan() {
 75 |     return this.type === Types.NAN;
 76 |   }
 77 | 
 78 |   /**
 79 |    * Returns true if this type is of type {@link OpenSCADNumber}.
 80 |    * @returns {boolean} True if this type is of type {@link OpenSCADNumber}.
 81 |    */
 82 |   isNumber() {
 83 |     return this.type === Types.NUMBER;
 84 |   }
 85 | 
 86 |   /**
 87 |    * Returns true if this type is of type {@link OpenSCADRange}.
 88 |    * @returns {boolean} True if this type is of type {@link OpenSCADBoolean}.
 89 |    */
 90 |   isRange() {
 91 |     return this.type === Types.RANGE;
 92 |   }
 93 | 
 94 |   /**
 95 |    * Returns true if this type is of type {@link OpenSCADString}.
 96 |    * @returns {boolean} True if this type is of type {@link OpenSCADString}.
 97 |    */
 98 |   isString() {
 99 |     return this.type === Types.STRING;
100 |   }
101 | 
102 |   /**
103 |    * Returns true if this type is of type {@link OpenSCADUndefined}.
104 |    * @returns {boolean} True if this type is of type {@link OpenSCADUndefined}.
105 |    */
106 |   isUndef() {
107 |     return this.type === Types.UNDEF;
108 |   }
109 | 
110 |   /**
111 |    * Returns true if this type is of type {@link OpenSCADVector}.
112 |    * @returns {boolean} True if this type is of type {@link OpenSCADVector}.
113 |    */
114 |   isVector() {
115 |     return this.type === Types.VECTOR;
116 |   }
117 | }
118 | 
119 | module.exports = Function;
120 |
121 |
122 | 123 | 124 | 125 | 126 |
127 | 128 | 131 | 132 |
133 | 134 | 137 | 138 | 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /docs/api_ThreeDModule.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: api/ThreeDModule.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: api/ThreeDModule.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
const {EOL} = require('os');
 30 | 
 31 | const AbstractModule = require('./AbstractModule');
 32 | const ThreeDModuleFile = require('../file/ThreeDModuleFile');
 33 | 
 34 | function getDimensionSize(vertices, index) {
 35 |   const range = vertices.reduce((accumulator, vertex) => {
 36 |     return {
 37 |       min: vertex[index] < accumulator.min ? vertex[index] : accumulator.min,
 38 |       max: vertex[index] > accumulator.max ? vertex[index] : accumulator.max,
 39 |     };
 40 |   }, {
 41 |     min: Number.POSITIVE_INFINITY,
 42 |     max: Number.NEGATIVE_INFINITY
 43 |   });
 44 | 
 45 |   return range.max - range.min;
 46 | }
 47 | 
 48 | function getVertex(content) {
 49 |   return content
 50 |     .split(' ')
 51 |     // Last three elements should be the co-ordinates, as a string
 52 |     .slice(-3)
 53 |     .map(vertex => parseFloat(vertex, 10));
 54 | }
 55 | 
 56 | function getVertices(contents) {
 57 |   const vertexRegex = new RegExp(/vertex([ ][0-9]+[.]*[0-9]*){3}/, 'gm');
 58 | 
 59 |   return contents
 60 |     .match(vertexRegex)
 61 |     .filter((value, index, self) => self.indexOf(value) === index)
 62 |     .map(vertexString => getVertex(vertexString));
 63 | }
 64 | 
 65 | function getTriangles(contents) {
 66 |   const triangleRegex = new RegExp(/outer loop[\s\S]+?endloop/, 'g');
 67 | 
 68 |   return contents
 69 |     .match(triangleRegex)
 70 |     .map(triangleString => triangleString.split(EOL))
 71 |     .map(triangleStrings => triangleStrings.splice(1, 3))
 72 |     .map(verticesOfTriangleStrings => {
 73 |       return verticesOfTriangleStrings.map(vertexString => getVertex(vertexString));
 74 |     });
 75 | }
 76 | 
 77 | /** @class */
 78 | class ThreeDModule extends AbstractModule {
 79 |   /** @param {Options} options */
 80 |   constructor(options) {
 81 |     super(options, ThreeDModuleFile);
 82 |     /**
 83 |      * @memberof ThreeDModule
 84 |      * @instance
 85 |      * @member {string} output The extracted output from execution of the .scad file.
 86 |      */
 87 | 
 88 |     /**
 89 |      * @memberof ThreeDModule
 90 |      * @instance
 91 |      * @function
 92 |      * @name isWithinBoundingBox
 93 |      * @param boundingBox {BoundingBox} The 3D box which the model should fit inside. It is considered 'within' if any coordinate is equal to, or within the box.
 94 |      * @returns {boolean} True if the model fits within the bounding box.
 95 |      */
 96 | 
 97 |     /**
 98 |      * @memberof ThreeDModule
 99 |      * @instance
100 |      * @member {Vertex[]} vertices A list of 3D vertices returned from the .scad file execution.
101 |      */
102 |     this.vertices = getVertices(this.output);
103 | 
104 |     /**
105 |      * @memberof ThreeDModule
106 |      * @instance
107 |      * @member {number} width The width of the model.
108 |      */
109 |     this.width = getDimensionSize(this.vertices, 0);
110 | 
111 |     /**
112 |      * @memberof ThreeDModule
113 |      * @instance
114 |      * @member {number} height The height of the model.
115 |      */
116 |     this.height = getDimensionSize(this.vertices, 1);
117 | 
118 |     /**
119 |      * @memberof ThreeDModule
120 |      * @instance
121 |      * @member {number} depth The depth of the model.
122 |      */
123 |     this.depth = getDimensionSize(this.vertices, 2);
124 | 
125 |     /**
126 |      * @typedef {Vertex[]} Triangle An array of three 3D vertices which describe a triangle. See {@link https://en.wikipedia.org/wiki/Triangle_mesh}.
127 |      */
128 | 
129 |     /**
130 |      * @memberof ThreeDModule
131 |      * @instance
132 |      * @member {Triangle[]} triangles The triangles which make up the model. See {@link https://en.wikipedia.org/wiki/Triangle_mesh}.
133 |      */
134 |     this.triangles = getTriangles(this.output);
135 |   }
136 | }
137 | 
138 | module.exports = ThreeDModule;
139 |
140 |
141 | 142 | 143 | 144 | 145 |
146 | 147 | 150 | 151 |
152 | 153 | 156 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /docs/api_TwoDModule.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: api/TwoDModule.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: api/TwoDModule.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
const xml2js = require('xml2js');
 30 | 
 31 | const AbstractModule = require('./AbstractModule');
 32 | const TwoDModuleFile = require('../file/TwoDModuleFile');
 33 | 
 34 | function getVertices(parsedOutput) {
 35 |   return parsedOutput.path
 36 |     .reduce((previousValue, currentValue) => {
 37 |       return previousValue.concat(currentValue.$.d.match(/(-*\d+,-*\d+)/g));
 38 |     }, [])
 39 |     .map(value => value
 40 |       .split(',')
 41 |       .map(point => parseFloat(point))
 42 |     );
 43 | }
 44 | 
 45 | /** @class */
 46 | class TwoDModule extends AbstractModule {
 47 |   /**
 48 |    * @param {Options} options
 49 |    */
 50 |   constructor(options) {
 51 |     super(options, TwoDModuleFile);
 52 | 
 53 |     /**
 54 |      * @memberof TwoDModule
 55 |      * @instance
 56 |      * @member {string} output The extracted output from execution of the .scad file.
 57 |      */
 58 | 
 59 |     /**
 60 |      * @memberof TwoDModule
 61 |      * @instance
 62 |      * @function
 63 |      * @name isWithinBoundingBox
 64 |      * @param boundingBox {BoundingBox} The 2D box which the model should fit inside. It is considered 'within' if any coordinate is equal to, or within the box.
 65 |      * @returns {boolean} True if the model fits within the bounding box.
 66 |      */
 67 | 
 68 |     xml2js.parseString(this.output, (error, result) => {
 69 |       if(error) {
 70 |         throw new Error(error);
 71 |       } else {
 72 |         /**
 73 |          * @memberof TwoDModule
 74 |          * @instance
 75 |          * @member {Vertex[]} vertices A list of 2D vertices returned from the .scad file execution.
 76 |          */
 77 |         this.vertices = getVertices(result.svg);
 78 | 
 79 |         /**
 80 |          * @memberof TwoDModule
 81 |          * @instance
 82 |          * @member {number} height The height of the model.
 83 |          */
 84 |         this.height = parseInt(result.svg.$.height, 10);
 85 |         /**
 86 |          * @memberof TwoDModule
 87 |          * @instance
 88 |          * @member {number} width The width of the model.
 89 |          */
 90 |         this.width = parseInt(result.svg.$.width, 10);
 91 |       }
 92 |     });
 93 |   }
 94 | }
 95 | 
 96 | module.exports = TwoDModule;
97 |
98 |
99 | 100 | 101 | 102 | 103 |
104 | 105 | 108 | 109 |
110 | 111 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HopefulLlama/UnitTestSCAD/ad8ac537c99dfc7f10d46839db2910f9b940e946/docs/fonts/OpenSans-Bold-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HopefulLlama/UnitTestSCAD/ad8ac537c99dfc7f10d46839db2910f9b940e946/docs/fonts/OpenSans-Bold-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-BoldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HopefulLlama/UnitTestSCAD/ad8ac537c99dfc7f10d46839db2910f9b940e946/docs/fonts/OpenSans-BoldItalic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-BoldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HopefulLlama/UnitTestSCAD/ad8ac537c99dfc7f10d46839db2910f9b940e946/docs/fonts/OpenSans-BoldItalic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HopefulLlama/UnitTestSCAD/ad8ac537c99dfc7f10d46839db2910f9b940e946/docs/fonts/OpenSans-Italic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HopefulLlama/UnitTestSCAD/ad8ac537c99dfc7f10d46839db2910f9b940e946/docs/fonts/OpenSans-Italic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HopefulLlama/UnitTestSCAD/ad8ac537c99dfc7f10d46839db2910f9b940e946/docs/fonts/OpenSans-Light-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HopefulLlama/UnitTestSCAD/ad8ac537c99dfc7f10d46839db2910f9b940e946/docs/fonts/OpenSans-Light-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-LightItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HopefulLlama/UnitTestSCAD/ad8ac537c99dfc7f10d46839db2910f9b940e946/docs/fonts/OpenSans-LightItalic-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-LightItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HopefulLlama/UnitTestSCAD/ad8ac537c99dfc7f10d46839db2910f9b940e946/docs/fonts/OpenSans-LightItalic-webfont.woff -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HopefulLlama/UnitTestSCAD/ad8ac537c99dfc7f10d46839db2910f9b940e946/docs/fonts/OpenSans-Regular-webfont.eot -------------------------------------------------------------------------------- /docs/fonts/OpenSans-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HopefulLlama/UnitTestSCAD/ad8ac537c99dfc7f10d46839db2910f9b940e946/docs/fonts/OpenSans-Regular-webfont.woff -------------------------------------------------------------------------------- /docs/global.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Global 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Global

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 |
30 | 31 |

32 | 33 | 34 |
35 | 36 |
37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 |
45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 |
78 | 79 | 80 | 81 | 82 |
83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 |

Type Definitions

102 | 103 | 104 | 105 |

BoundingBox

106 | 107 | 108 | 109 | 110 |
111 | A box in 2D/3D space. 112 |
113 | 114 | 115 | 116 |
Type:
117 |
    118 |
  • 119 | 120 | object 121 | 122 | 123 |
  • 124 |
125 | 126 | 127 | 128 | 129 | 130 |
Properties:
131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 |
NameTypeDescription
min 160 | 161 | 162 | Vertex 163 | 164 | 165 | 166 | A 2D/3D vertex which defines the 'minimum' co-ordinates. This is the corner of the box with the lowest x, y and optional z co-ordinate.
max 183 | 184 | 185 | Vertex 186 | 187 | 188 | 189 | A 2D/3D vertex which defines the 'maximum' co-ordinates. This is the corner of the box with the highest x, y and optional z co-ordinate.
201 | 202 | 203 | 204 | 205 |
206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 |
Source:
233 |
236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 |
244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 |

OpenSCADBoolean

253 | 254 | 255 | 256 | 257 |
258 | Represents an OpenSCAD boolean. Equal to 'boolean'. 259 |
260 | 261 | 262 | 263 |
Type:
264 |
    265 |
  • 266 | 267 | string 268 | 269 | 270 |
  • 271 |
272 | 273 | 274 | 275 | 276 | 277 |
278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 |
Source:
305 |
308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 |
316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 |

OpenSCADInfinity

325 | 326 | 327 | 328 | 329 |
330 | Represents Infinity in OpenSCAD. Equal to 'inf'. 331 |
332 | 333 | 334 | 335 |
Type:
336 |
    337 |
  • 338 | 339 | string 340 | 341 | 342 |
  • 343 |
344 | 345 | 346 | 347 | 348 | 349 |
350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 |
Source:
377 |
380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 |
388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 |

OpenSCADNaN

397 | 398 | 399 | 400 | 401 |
402 | Represents NaN (Not a Number) in OpenSCAD. Equal to 'nan'. 403 |
404 | 405 | 406 | 407 |
Type:
408 |
    409 |
  • 410 | 411 | string 412 | 413 | 414 |
  • 415 |
416 | 417 | 418 | 419 | 420 | 421 |
422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 |
Source:
449 |
452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 |
460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 |

OpenSCADNumber

469 | 470 | 471 | 472 | 473 |
474 | Represents an OpenSCAD number. Equal to 'number'. 475 |
476 | 477 | 478 | 479 |
Type:
480 |
    481 |
  • 482 | 483 | string 484 | 485 | 486 |
  • 487 |
488 | 489 | 490 | 491 | 492 | 493 |
494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 |
Source:
521 |
524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 |
532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 |

OpenSCADRange

541 | 542 | 543 | 544 | 545 |
546 | Represents an OpenSCAD range. Equal to 'range'. 547 |
548 | 549 | 550 | 551 |
Type:
552 |
    553 |
  • 554 | 555 | string 556 | 557 | 558 |
  • 559 |
560 | 561 | 562 | 563 | 564 | 565 |
566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 |
Source:
593 |
596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 |
604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 |

OpenSCADString

613 | 614 | 615 | 616 | 617 |
618 | Represents an OpenSCAD string. Equal to 'string'. 619 |
620 | 621 | 622 | 623 |
Type:
624 |
    625 |
  • 626 | 627 | string 628 | 629 | 630 |
  • 631 |
632 | 633 | 634 | 635 | 636 | 637 |
638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 |
Source:
665 |
668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 |
676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 |

OpenSCADUndefined

685 | 686 | 687 | 688 | 689 |
690 | Represents undef (undefined) in OpenSCAD. Equal to 'undefined'. 691 |
692 | 693 | 694 | 695 |
Type:
696 |
    697 |
  • 698 | 699 | string 700 | 701 | 702 |
  • 703 |
704 | 705 | 706 | 707 | 708 | 709 |
710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 |
Source:
737 |
740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 |
748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 |

OpenSCADVector

757 | 758 | 759 | 760 | 761 |
762 | Represents an OpenSCAD vector. Equal to 'vector'. 763 |
764 | 765 | 766 | 767 |
Type:
768 |
    769 |
  • 770 | 771 | string 772 | 773 | 774 |
  • 775 |
776 | 777 | 778 | 779 | 780 | 781 |
782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 |
Source:
809 |
812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 |
820 | 821 | 822 | 823 | 824 | 825 | 826 | 827 | 828 |

Options

829 | 830 | 831 | 832 | 833 |
834 | Key/value pair of options to configure the execution of an OpenSCAD test. 835 |
836 | 837 | 838 | 839 |
Type:
840 |
    841 |
  • 842 | 843 | object 844 | 845 | 846 |
  • 847 |
848 | 849 | 850 | 851 | 852 | 853 |
Properties:
854 | 855 | 856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 913 | 914 | 915 | 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 936 | 937 | 938 | 939 | 940 | 941 | 942 | 943 | 944 | 945 | 946 | 947 | 948 | 949 | 950 | 951 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | 969 | 970 | 971 | 972 | 973 | 974 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 989 | 990 | 991 | 992 |
NameTypeDescription
openSCADDirectory 883 | 884 | 885 | String 886 | 887 | 888 | 889 | The prefix to prepend to all uses/includes.
use 906 | 907 | 908 | Array.<String> 909 | 910 | 911 | 912 | List of .scad files to import as 'use'.
include 929 | 930 | 931 | Array.<String> 932 | 933 | 934 | 935 | List of .scad files to import as 'include'.
setUpText 952 | 953 | 954 | String 955 | 956 | 957 | 958 | Any required OpenSCAD code to set up the test.
testText 975 | 976 | 977 | String 978 | 979 | 980 | 981 | The OpenSCAD code to be tested and asserted on.
993 | 994 | 995 | 996 | 997 |
998 | 999 | 1000 | 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 |
Source:
1025 |
1028 | 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 |
1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | 1044 |

Triangle

1045 | 1046 | 1047 | 1048 | 1049 |
1050 | An array of three 3D vertices which describe a triangle. See https://en.wikipedia.org/wiki/Triangle_mesh. 1051 |
1052 | 1053 | 1054 | 1055 |
Type:
1056 |
    1057 |
  • 1058 | 1059 | Array.<Vertex> 1060 | 1061 | 1062 |
  • 1063 |
1064 | 1065 | 1066 | 1067 | 1068 | 1069 |
1070 | 1071 | 1072 | 1073 | 1074 | 1075 | 1076 | 1077 | 1078 | 1079 | 1080 | 1081 | 1082 | 1083 | 1084 | 1085 | 1086 | 1087 | 1088 | 1089 | 1090 | 1091 | 1092 | 1093 | 1094 | 1095 | 1096 |
Source:
1097 |
1100 | 1101 | 1102 | 1103 | 1104 | 1105 | 1106 | 1107 |
1108 | 1109 | 1110 | 1111 | 1112 | 1113 | 1114 | 1115 | 1116 |

Types

1117 | 1118 | 1119 | 1120 | 1121 |
1122 | A collection of the available OpenSCAD types. 1123 |
1124 | 1125 | 1126 | 1127 |
Type:
1128 |
    1129 |
  • 1130 | 1131 | object 1132 | 1133 | 1134 |
  • 1135 |
1136 | 1137 | 1138 | 1139 | 1140 | 1141 |
Properties:
1142 | 1143 | 1144 | 1145 | 1146 | 1147 | 1148 | 1149 | 1150 | 1151 | 1152 | 1153 | 1154 | 1155 | 1156 | 1157 | 1158 | 1159 | 1160 | 1161 | 1162 | 1163 | 1164 | 1165 | 1166 | 1167 | 1168 | 1169 | 1170 | 1178 | 1179 | 1180 | 1181 | 1182 | 1183 | 1184 | 1185 | 1186 | 1187 | 1188 | 1189 | 1190 | 1191 | 1192 | 1193 | 1201 | 1202 | 1203 | 1204 | 1205 | 1206 | 1207 | 1208 | 1209 | 1210 | 1211 | 1212 | 1213 | 1214 | 1215 | 1216 | 1224 | 1225 | 1226 | 1227 | 1228 | 1229 | 1230 | 1231 | 1232 | 1233 | 1234 | 1235 | 1236 | 1237 | 1238 | 1239 | 1247 | 1248 | 1249 | 1250 | 1251 | 1252 | 1253 | 1254 | 1255 | 1256 | 1257 | 1258 | 1259 | 1260 | 1261 | 1262 | 1270 | 1271 | 1272 | 1273 | 1274 | 1275 | 1276 | 1277 | 1278 | 1279 | 1280 | 1281 | 1282 | 1283 | 1284 | 1285 | 1293 | 1294 | 1295 | 1296 | 1297 | 1298 | 1299 | 1300 | 1301 | 1302 | 1303 | 1304 | 1305 | 1306 | 1307 | 1308 | 1316 | 1317 | 1318 | 1319 | 1320 | 1321 | 1322 | 1323 | 1324 | 1325 | 1326 | 1327 | 1328 | 1329 | 1330 | 1331 | 1339 | 1340 | 1341 | 1342 | 1343 | 1344 | 1345 | 1346 | 1347 | 1348 | 1349 |
NameTypeDescription
BOOLEAN 1171 | 1172 | 1173 | OpenSCADBoolean 1174 | 1175 | 1176 | 1177 | See OpenSCADBoolean.
INF 1194 | 1195 | 1196 | OpenSCADInfinity 1197 | 1198 | 1199 | 1200 | See OpenSCADInfinity.
NAN 1217 | 1218 | 1219 | OpenSCADNaN 1220 | 1221 | 1222 | 1223 | See OpenSCADNaN.
NUMBER 1240 | 1241 | 1242 | OpenSCADNumber 1243 | 1244 | 1245 | 1246 | See OpenSCADNumber.
RANGE 1263 | 1264 | 1265 | OpenSCADRange 1266 | 1267 | 1268 | 1269 | See OpenSCADRange.
STRING 1286 | 1287 | 1288 | OpenSCADString 1289 | 1290 | 1291 | 1292 | See OpenSCADString.
UNDEF 1309 | 1310 | 1311 | OpenSCADUndefined 1312 | 1313 | 1314 | 1315 | See OpenSCADUndefined.
VECTOR 1332 | 1333 | 1334 | OpenSCADVector 1335 | 1336 | 1337 | 1338 | See OpenSCADVector.
1350 | 1351 | 1352 | 1353 | 1354 |
1355 | 1356 | 1357 | 1358 | 1359 | 1360 | 1361 | 1362 | 1363 | 1364 | 1365 | 1366 | 1367 | 1368 | 1369 | 1370 | 1371 | 1372 | 1373 | 1374 | 1375 | 1376 | 1377 | 1378 | 1379 | 1380 | 1381 |
Source:
1382 |
1385 | 1386 | 1387 | 1388 | 1389 | 1390 | 1391 | 1392 |
1393 | 1394 | 1395 | 1396 | 1397 | 1398 | 1399 | 1400 | 1401 |

UnitTestSCAD

1402 | 1403 | 1404 | 1405 | 1406 |
1407 | This is the top level object exposed when requiring UnitTestSCAD into a NodeJS script. 1408 |
1409 | 1410 | 1411 | 1412 |
Type:
1413 |
    1414 |
  • 1415 | 1416 | object 1417 | 1418 | 1419 |
  • 1420 |
1421 | 1422 | 1423 | 1424 | 1425 | 1426 |
Properties:
1427 | 1428 | 1429 | 1430 | 1431 | 1432 | 1433 | 1434 | 1435 | 1436 | 1437 | 1438 | 1439 | 1440 | 1441 | 1442 | 1443 | 1444 | 1445 | 1446 | 1447 | 1448 | 1449 | 1450 | 1451 | 1452 | 1453 | 1454 | 1455 | 1463 | 1464 | 1465 | 1466 | 1467 | 1468 | 1469 | 1470 | 1471 | 1472 | 1473 | 1474 | 1475 | 1476 | 1477 | 1478 | 1486 | 1487 | 1488 | 1489 | 1490 | 1491 | 1492 | 1493 | 1494 | 1495 | 1496 | 1497 | 1498 | 1499 | 1500 | 1501 | 1509 | 1510 | 1511 | 1512 | 1513 | 1514 | 1515 | 1516 | 1517 | 1518 | 1519 | 1520 | 1521 | 1522 | 1523 | 1524 | 1532 | 1533 | 1534 | 1535 | 1536 | 1537 | 1538 | 1539 | 1540 | 1541 | 1542 |
NameTypeDescription
Function 1456 | 1457 | 1458 | function 1459 | 1460 | 1461 | 1462 | Exposes the Function class for use. This should be used when testing an OpenSCAD function.
ThreeDModule 1479 | 1480 | 1481 | ThreeDModule 1482 | 1483 | 1484 | 1485 | Exposes the ThreeDModule class for use. This should be used when testing an OpenSCAD module which produces a 3D model.
TwoDModule 1502 | 1503 | 1504 | TwoDModule 1505 | 1506 | 1507 | 1508 | Exposes the TwoDModule class for use. This should be used when testing an OpenSCAD module which produces a 2D model.
Types 1525 | 1526 | 1527 | Types 1528 | 1529 | 1530 | 1531 | Exposes the Types object for use. This should be used when performing assertions on a Function.
1543 | 1544 | 1545 | 1546 | 1547 |
1548 | 1549 | 1550 | 1551 | 1552 | 1553 | 1554 | 1555 | 1556 | 1557 | 1558 | 1559 | 1560 | 1561 | 1562 | 1563 | 1564 | 1565 | 1566 | 1567 | 1568 | 1569 | 1570 | 1571 | 1572 | 1573 | 1574 |
Source:
1575 |
1578 | 1579 | 1580 | 1581 | 1582 | 1583 | 1584 | 1585 |
1586 | 1587 | 1588 | 1589 | 1590 | 1591 | 1592 | 1593 | 1594 |

Vertex

1595 | 1596 | 1597 | 1598 | 1599 |
1600 | A 2/3 length co-ordinate representing a point in 2D/3D space. 1601 |
1602 | 1603 | 1604 | 1605 |
Type:
1606 |
    1607 |
  • 1608 | 1609 | Array.<number> 1610 | 1611 | 1612 |
  • 1613 |
1614 | 1615 | 1616 | 1617 | 1618 | 1619 |
1620 | 1621 | 1622 | 1623 | 1624 | 1625 | 1626 | 1627 | 1628 | 1629 | 1630 | 1631 | 1632 | 1633 | 1634 | 1635 | 1636 | 1637 | 1638 | 1639 | 1640 | 1641 | 1642 | 1643 | 1644 | 1645 | 1646 |
Source:
1647 |
1650 | 1651 | 1652 | 1653 | 1654 | 1655 | 1656 | 1657 |
1658 | 1659 | 1660 | 1661 | 1662 | 1663 | 1664 | 1665 | 1666 | 1667 | 1668 |
1669 | 1670 |
1671 | 1672 | 1673 | 1674 | 1675 |
1676 | 1677 | 1680 | 1681 |
1682 | 1683 | 1686 | 1687 | 1688 | 1689 | 1690 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Home 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Home

21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |

30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 | 52 | 55 | 56 |
57 | 58 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /docs/index.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: index.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: index.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
const OpenSCADFunction = require('./api/OpenSCADFunction');
30 | const ThreeDModule = require('./api/ThreeDModule');
31 | const TwoDModule = require('./api/TwoDModule');
32 | const Types = require('./types/Types');
33 | 
34 | /**
35 |  * @typedef {object} UnitTestSCAD This is the top level object exposed when requiring UnitTestSCAD into a NodeJS script.
36 |  * @property {Function} Function Exposes the {@link Function} class for use. This should be used when testing an OpenSCAD function.
37 |  * @property {ThreeDModule} ThreeDModule Exposes the {@link ThreeDModule} class for use. This should be used when testing an OpenSCAD module which produces a 3D model.
38 |  * @property {TwoDModule} TwoDModule Exposes the {@link TwoDModule} class for use. This should be used when testing an OpenSCAD module which produces a 2D model.
39 |  * @property {Types} Types Exposes the {@link Types} object for use. This should be used when performing assertions on a {@link Function}.
40 |  */
41 | module.exports = {
42 |   Function: OpenSCADFunction,
43 |   ThreeDModule,
44 |   TwoDModule,
45 |   Types
46 | };
47 |
48 |
49 | 50 | 51 | 52 | 53 |
54 | 55 | 58 | 59 |
60 | 61 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /docs/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (function() { 3 | var source = document.getElementsByClassName('prettyprint source linenums'); 4 | var i = 0; 5 | var lineNumber = 0; 6 | var lineId; 7 | var lines; 8 | var totalLines; 9 | var anchorHash; 10 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = 'line' + lineNumber; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /docs/scripts/prettify/Apache-License-2.0.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /docs/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", 2 | /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /docs/scripts/prettify/prettify.js: -------------------------------------------------------------------------------- 1 | var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; 2 | (function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= 3 | [],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), 9 | l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, 10 | q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, 11 | q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, 12 | "");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), 13 | a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} 14 | for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], 18 | "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], 19 | H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], 20 | J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ 21 | I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), 22 | ["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", 23 | /^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), 24 | ["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", 25 | hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= 26 | !k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p th:last-child { border-right: 1px solid #ddd; } 224 | 225 | .ancestors, .attribs { color: #999; } 226 | .ancestors a, .attribs a 227 | { 228 | color: #999 !important; 229 | text-decoration: none; 230 | } 231 | 232 | .clear 233 | { 234 | clear: both; 235 | } 236 | 237 | .important 238 | { 239 | font-weight: bold; 240 | color: #950B02; 241 | } 242 | 243 | .yes-def { 244 | text-indent: -1000px; 245 | } 246 | 247 | .type-signature { 248 | color: #aaa; 249 | } 250 | 251 | .name, .signature { 252 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 253 | } 254 | 255 | .details { margin-top: 14px; border-left: 2px solid #DDD; } 256 | .details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; } 257 | .details dd { margin-left: 70px; } 258 | .details ul { margin: 0; } 259 | .details ul { list-style-type: none; } 260 | .details li { margin-left: 30px; padding-top: 6px; } 261 | .details pre.prettyprint { margin: 0 } 262 | .details .object-value { padding-top: 0; } 263 | 264 | .description { 265 | margin-bottom: 1em; 266 | margin-top: 1em; 267 | } 268 | 269 | .code-caption 270 | { 271 | font-style: italic; 272 | font-size: 107%; 273 | margin: 0; 274 | } 275 | 276 | .prettyprint 277 | { 278 | border: 1px solid #ddd; 279 | width: 80%; 280 | overflow: auto; 281 | } 282 | 283 | .prettyprint.source { 284 | width: inherit; 285 | } 286 | 287 | .prettyprint code 288 | { 289 | font-size: 100%; 290 | line-height: 18px; 291 | display: block; 292 | padding: 4px 12px; 293 | margin: 0; 294 | background-color: #fff; 295 | color: #4D4E53; 296 | } 297 | 298 | .prettyprint code span.line 299 | { 300 | display: inline-block; 301 | } 302 | 303 | .prettyprint.linenums 304 | { 305 | padding-left: 70px; 306 | -webkit-user-select: none; 307 | -moz-user-select: none; 308 | -ms-user-select: none; 309 | user-select: none; 310 | } 311 | 312 | .prettyprint.linenums ol 313 | { 314 | padding-left: 0; 315 | } 316 | 317 | .prettyprint.linenums li 318 | { 319 | border-left: 3px #ddd solid; 320 | } 321 | 322 | .prettyprint.linenums li.selected, 323 | .prettyprint.linenums li.selected * 324 | { 325 | background-color: lightyellow; 326 | } 327 | 328 | .prettyprint.linenums li * 329 | { 330 | -webkit-user-select: text; 331 | -moz-user-select: text; 332 | -ms-user-select: text; 333 | user-select: text; 334 | } 335 | 336 | .params .name, .props .name, .name code { 337 | color: #4D4E53; 338 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 339 | font-size: 100%; 340 | } 341 | 342 | .params td.description > p:first-child, 343 | .props td.description > p:first-child 344 | { 345 | margin-top: 0; 346 | padding-top: 0; 347 | } 348 | 349 | .params td.description > p:last-child, 350 | .props td.description > p:last-child 351 | { 352 | margin-bottom: 0; 353 | padding-bottom: 0; 354 | } 355 | 356 | .disabled { 357 | color: #454545; 358 | } 359 | -------------------------------------------------------------------------------- /docs/styles/prettify-jsdoc.css: -------------------------------------------------------------------------------- 1 | /* JSDoc prettify.js theme */ 2 | 3 | /* plain text */ 4 | .pln { 5 | color: #000000; 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | 10 | /* string content */ 11 | .str { 12 | color: #006400; 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | 17 | /* a keyword */ 18 | .kwd { 19 | color: #000000; 20 | font-weight: bold; 21 | font-style: normal; 22 | } 23 | 24 | /* a comment */ 25 | .com { 26 | font-weight: normal; 27 | font-style: italic; 28 | } 29 | 30 | /* a type name */ 31 | .typ { 32 | color: #000000; 33 | font-weight: normal; 34 | font-style: normal; 35 | } 36 | 37 | /* a literal value */ 38 | .lit { 39 | color: #006400; 40 | font-weight: normal; 41 | font-style: normal; 42 | } 43 | 44 | /* punctuation */ 45 | .pun { 46 | color: #000000; 47 | font-weight: bold; 48 | font-style: normal; 49 | } 50 | 51 | /* lisp open bracket */ 52 | .opn { 53 | color: #000000; 54 | font-weight: bold; 55 | font-style: normal; 56 | } 57 | 58 | /* lisp close bracket */ 59 | .clo { 60 | color: #000000; 61 | font-weight: bold; 62 | font-style: normal; 63 | } 64 | 65 | /* a markup tag name */ 66 | .tag { 67 | color: #006400; 68 | font-weight: normal; 69 | font-style: normal; 70 | } 71 | 72 | /* a markup attribute name */ 73 | .atn { 74 | color: #006400; 75 | font-weight: normal; 76 | font-style: normal; 77 | } 78 | 79 | /* a markup attribute value */ 80 | .atv { 81 | color: #006400; 82 | font-weight: normal; 83 | font-style: normal; 84 | } 85 | 86 | /* a declaration */ 87 | .dec { 88 | color: #000000; 89 | font-weight: bold; 90 | font-style: normal; 91 | } 92 | 93 | /* a variable name */ 94 | .var { 95 | color: #000000; 96 | font-weight: normal; 97 | font-style: normal; 98 | } 99 | 100 | /* a function name */ 101 | .fun { 102 | color: #000000; 103 | font-weight: bold; 104 | font-style: normal; 105 | } 106 | 107 | /* Specify class=linenums on a pre to get line numbering */ 108 | ol.linenums { 109 | margin-top: 0; 110 | margin-bottom: 0; 111 | } 112 | -------------------------------------------------------------------------------- /docs/styles/prettify-tomorrow.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Theme */ 2 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 3 | /* Pretty printing styles. Used with prettify.js. */ 4 | /* SPAN elements with the classes below are added by prettyprint. */ 5 | /* plain text */ 6 | .pln { 7 | color: #4d4d4c; } 8 | 9 | @media screen { 10 | /* string content */ 11 | .str { 12 | color: #718c00; } 13 | 14 | /* a keyword */ 15 | .kwd { 16 | color: #8959a8; } 17 | 18 | /* a comment */ 19 | .com { 20 | color: #8e908c; } 21 | 22 | /* a type name */ 23 | .typ { 24 | color: #4271ae; } 25 | 26 | /* a literal value */ 27 | .lit { 28 | color: #f5871f; } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #4d4d4c; } 33 | 34 | /* lisp open bracket */ 35 | .opn { 36 | color: #4d4d4c; } 37 | 38 | /* lisp close bracket */ 39 | .clo { 40 | color: #4d4d4c; } 41 | 42 | /* a markup tag name */ 43 | .tag { 44 | color: #c82829; } 45 | 46 | /* a markup attribute name */ 47 | .atn { 48 | color: #f5871f; } 49 | 50 | /* a markup attribute value */ 51 | .atv { 52 | color: #3e999f; } 53 | 54 | /* a declaration */ 55 | .dec { 56 | color: #f5871f; } 57 | 58 | /* a variable name */ 59 | .var { 60 | color: #c82829; } 61 | 62 | /* a function name */ 63 | .fun { 64 | color: #4271ae; } } 65 | /* Use higher contrast and text-weight for printable form. */ 66 | @media print, projection { 67 | .str { 68 | color: #060; } 69 | 70 | .kwd { 71 | color: #006; 72 | font-weight: bold; } 73 | 74 | .com { 75 | color: #600; 76 | font-style: italic; } 77 | 78 | .typ { 79 | color: #404; 80 | font-weight: bold; } 81 | 82 | .lit { 83 | color: #044; } 84 | 85 | .pun, .opn, .clo { 86 | color: #440; } 87 | 88 | .tag { 89 | color: #006; 90 | font-weight: bold; } 91 | 92 | .atn { 93 | color: #404; } 94 | 95 | .atv { 96 | color: #060; } } 97 | /* Style */ 98 | /* 99 | pre.prettyprint { 100 | background: white; 101 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 102 | font-size: 12px; 103 | line-height: 1.5; 104 | border: 1px solid #ccc; 105 | padding: 10px; } 106 | */ 107 | 108 | /* Specify class=linenums on a pre to get line numbering */ 109 | ol.linenums { 110 | margin-top: 0; 111 | margin-bottom: 0; } 112 | 113 | /* IE indents via margin-left */ 114 | li.L0, 115 | li.L1, 116 | li.L2, 117 | li.L3, 118 | li.L4, 119 | li.L5, 120 | li.L6, 121 | li.L7, 122 | li.L8, 123 | li.L9 { 124 | /* */ } 125 | 126 | /* Alternate shading for lines */ 127 | li.L1, 128 | li.L3, 129 | li.L5, 130 | li.L7, 131 | li.L9 { 132 | /* */ } 133 | -------------------------------------------------------------------------------- /docs/types_Types.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: types/Types.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: types/Types.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/** @typedef {string} OpenSCADBoolean Represents an OpenSCAD boolean. Equal to 'boolean'. */
30 | /** @typedef {string} OpenSCADInfinity Represents Infinity in OpenSCAD. Equal to 'inf'. */
31 | /** @typedef {string} OpenSCADNaN Represents NaN (Not a Number) in OpenSCAD. Equal to 'nan'. */
32 | /** @typedef {string} OpenSCADNumber Represents an OpenSCAD number. Equal to 'number'. */
33 | /** @typedef {string} OpenSCADRange Represents an OpenSCAD range. Equal to 'range'. */
34 | /** @typedef {string} OpenSCADString Represents an OpenSCAD string. Equal to 'string'. */
35 | /** @typedef {string} OpenSCADUndefined Represents undef (undefined) in OpenSCAD. Equal to 'undefined'. */
36 | /** @typedef {string} OpenSCADVector Represents an OpenSCAD vector. Equal to 'vector'. */
37 | 
38 | /**
39 |  * @typedef {object} Types A collection of the available OpenSCAD types.
40 |  * @property {OpenSCADBoolean} BOOLEAN See {@link OpenSCADBoolean}.
41 |  * @property {OpenSCADInfinity} INF See {@link OpenSCADInfinity}.
42 |  * @property {OpenSCADNaN} NAN See {@link OpenSCADNaN}.
43 |  * @property {OpenSCADNumber} NUMBER See {@link OpenSCADNumber}.
44 |  * @property {OpenSCADRange} RANGE See {@link OpenSCADRange}.
45 |  * @property {OpenSCADString} STRING See {@link OpenSCADString}.
46 |  * @property {OpenSCADUndefined} UNDEF See {@link OpenSCADUndefined}.
47 |  * @property {OpenSCADVector} VECTOR See {@link OpenSCADVector}.
48 |  */
49 | module.exports = {
50 |   BOOLEAN: 'boolean',
51 |   INF: 'inf',
52 |   NAN: 'nan',
53 |   NUMBER: 'number',
54 |   RANGE: 'range',
55 |   STRING: 'string',
56 |   UNDEF: 'undef',
57 |   VECTOR: 'vector',
58 | };
59 |
60 |
61 | 62 | 63 | 64 | 65 |
66 | 67 | 70 | 71 |
72 | 73 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /jsdoc.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "templates": { 3 | "default": { 4 | "includeDate": false 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /llama-rlsr.config.js: -------------------------------------------------------------------------------- 1 | const child_process = require('child_process'); 2 | const fs = require('fs') 3 | const path = require('path'); 4 | 5 | const LlamaRlsrKeepAChangelog = require('llama-rlsr-keep-a-changelog'); 6 | const LlamaRlsrNpm = require('llama-rlsr-npm'); 7 | const simpleGit = require('simple-git')(process.cwd()); 8 | const GitHubApi = require('github-api'); 9 | const rimraf = require('rimraf'); 10 | 11 | const gitHubCredentials = require('./credentials/github.json'); 12 | 13 | const username = 'HopefulLlama'; 14 | const repoName = 'UnitTestSCAD'; 15 | 16 | if(!gitHubCredentials) { 17 | throw new Error('GitHub credentials not found.'); 18 | } 19 | 20 | module.exports = { 21 | preRelease: [ 22 | LlamaRlsrNpm.updateVersion(), 23 | (_, done) => { 24 | const packageLock = path.join(__dirname, 'package-lock.json'); 25 | 26 | rimraf.sync(path.join(__dirname, 'node_modules')); 27 | 28 | if(fs.existsSync(packageLock)) { 29 | fs.unlinkSync(packageLock); 30 | } 31 | 32 | child_process.execSync('npm i'); 33 | 34 | done(); 35 | }, 36 | LlamaRlsrKeepAChangelog.updateChangelog({ 37 | placeholder: '- Nothing yet' 38 | }), 39 | LlamaRlsrKeepAChangelog.updateDiff({ 40 | urlGenerator: (oldVersion, newVersion) => `https://github.com/${username}/${repoName}/compare/${oldVersion}...${newVersion}`, 41 | latest: 'HEAD', 42 | tag: { 43 | prefix: 'v' 44 | } 45 | }) 46 | ], 47 | release: [ 48 | (versionMetadata, done) => { 49 | simpleGit.add(['package.json', 'package-lock.json', 'CHANGELOG.md', 'llama-rlsr.metadata.json'], () => { 50 | simpleGit.commit(`Update to version ${versionMetadata.newVersion}`, () => { 51 | simpleGit.addTag(`v${versionMetadata.newVersion}`, () => { 52 | simpleGit.push('origin', 'master', () => { 53 | simpleGit.pushTags('origin', () => done()); 54 | }); 55 | }); 56 | }); 57 | }); 58 | }, 59 | (versionMetadata, done) => { 60 | const gitHub = new GitHubApi(gitHubCredentials); 61 | gitHub 62 | .getRepo(username, repoName) 63 | .createRelease({"tag_name": `v${versionMetadata.newVersion}`}, () => done()); 64 | } 65 | ] 66 | }; -------------------------------------------------------------------------------- /llama-rlsr.metadata.json: -------------------------------------------------------------------------------- 1 | {"oldVersion":"3.0.3"} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "unittestscad", 3 | "version": "3.0.3", 4 | "description": "UnitTestSCAD: Unit Testing for OpenSCAD", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "lint-src": "eslint -c .eslintrc.src.json ./src/**/*.js", 8 | "lint-spec": "eslint -c .eslintrc.spec.json ./spec/**/*.js", 9 | "lint": "npm run lint-src && npm run lint-spec", 10 | "lint-fix": "npm run lint-src -- --fix && npm run lint-spec -- --fix", 11 | "unit-test": "nyc jasmine \"./spec/unit/**/*Spec.js\"", 12 | "integration-test": "nyc --no-clean jasmine \"./spec/integration/**/*Spec.js\"", 13 | "test": "npm run lint && npm run unit-test && npm run integration-test", 14 | "precommit": "lint-staged && npm run doc && git add docs", 15 | "doc": "jsdoc -r ./src -d docs -c ./jsdoc.conf.json", 16 | "release": "node node_modules/llama-rlsr/src/llama-rlsr.js llama-rlsr.config.js", 17 | "coverage-report": "nyc report --reporter=html" 18 | }, 19 | "lint-staged": { 20 | "./src/**/*.js": [ 21 | "npm run lint-src -- --fix", 22 | "git add" 23 | ], 24 | "./spec/**/*.js": [ 25 | "npm run lint-spec -- --fix", 26 | "git add" 27 | ] 28 | }, 29 | "repository": { 30 | "type": "git", 31 | "url": "git+https://github.com/HopefulLlama/UnitTestSCAD.git" 32 | }, 33 | "keywords": [ 34 | "unit", 35 | "test", 36 | "openscad" 37 | ], 38 | "author": "Jonathan Law", 39 | "license": "MIT", 40 | "bugs": { 41 | "url": "https://github.com/HopefulLlama/UnitTestSCAD/issues" 42 | }, 43 | "homepage": "https://github.com/HopefulLlama/UnitTestSCAD#readme", 44 | "dependencies": { 45 | "xml2js": "^0.4.17" 46 | }, 47 | "devDependencies": { 48 | "eslint": "^5.5.0", 49 | "eslint-plugin-jasmine": "^2.10.1", 50 | "github-api": "^3.0.0", 51 | "husky": "^0.14.3", 52 | "jasmine": "^3.2.0", 53 | "jsdoc": "^3.5.5", 54 | "lint-staged": "^7.2.2", 55 | "llama-rlsr": "0.0.6", 56 | "llama-rlsr-keep-a-changelog": "0.0.4", 57 | "llama-rlsr-npm": "0.0.2", 58 | "nyc": "^13.0.1", 59 | "proxyquire": "^2.1.0", 60 | "rimraf": "^2.6.2", 61 | "simple-git": "^1.98.0", 62 | "sinon": "^6.1.5" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /spec/integration/_resources/garbage.scad: -------------------------------------------------------------------------------- 1 | garbage -------------------------------------------------------------------------------- /spec/integration/_utils/FileUtils.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | const tempFiles = [ 4 | 'UnitTestSCAD_48967_TEMP_DELETE-ME_SCAD.scad', 5 | 'UnitTestSCAD_48967_TEMP_DELETE-ME_FUNCTION.stl', 6 | 'UnitTestSCAD_48967_TEMP_DELETE-ME_THREE_D.stl', 7 | 'UnitTestSCAD_48967_TEMP_DELETE-ME_TWO_D.svg', 8 | ]; 9 | 10 | module.exports = { 11 | checkClean() { 12 | tempFiles.forEach(tempFile => expect(fs.existsSync(tempFile)).toBe(false, tempFile)); 13 | } 14 | }; -------------------------------------------------------------------------------- /spec/integration/function/FunctionSpec.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const UnitTestSCAD = require('../../../src'); 4 | const FileUtils = require('../_utils/FileUtils'); 5 | 6 | const openSCADDirectory = path.join(__dirname, '_resources'); 7 | 8 | const boolean = { 9 | file: 'boolean.scad', 10 | method: 'isBoolean', 11 | type: UnitTestSCAD.Types.BOOLEAN, 12 | }; 13 | const inf = { 14 | file: 'inf.scad', 15 | method: 'isInf', 16 | type: UnitTestSCAD.Types.INF, 17 | }; 18 | const nan = { 19 | file: 'nan.scad', 20 | method: 'isNan', 21 | type: UnitTestSCAD.Types.NAN, 22 | }; 23 | const number = { 24 | file: 'number.scad', 25 | method: 'isNumber', 26 | type: UnitTestSCAD.Types.NUMBER, 27 | }; 28 | const range = { 29 | file: 'range.scad', 30 | method: 'isRange', 31 | type: UnitTestSCAD.Types.RANGE, 32 | }; 33 | const string = { 34 | file: 'string.scad', 35 | method: 'isString', 36 | type: UnitTestSCAD.Types.STRING, 37 | }; 38 | const undef = { 39 | file: 'undef.scad', 40 | method: 'isUndef', 41 | type: UnitTestSCAD.Types.UNDEF, 42 | }; 43 | const vector = { 44 | file: 'vector.scad', 45 | method: 'isVector', 46 | type: UnitTestSCAD.Types.VECTOR, 47 | }; 48 | const types = [boolean, inf, nan, number, range, string, undef, vector]; 49 | 50 | describe('FunctionSpec', () => { 51 | 52 | afterEach(() => FileUtils.checkClean()); 53 | 54 | types.forEach(type => { 55 | describe(type.type, () => { 56 | let testee; 57 | 58 | beforeEach(() => { 59 | testee = new UnitTestSCAD.Function({ 60 | openSCADDirectory, 61 | use: [type.file], 62 | testText: 'test();' 63 | }); 64 | }); 65 | 66 | it('should be the correct type', () => expect(testee.type).toBe(type.type)); 67 | it(`${type.method} should be true`, () => expect(testee[type.method]()).toBe(true, type.method)); 68 | 69 | types 70 | .filter(notType => notType !== type) 71 | .forEach(notType => { 72 | it(`${notType.method} should be false`, () => expect(testee[notType.method]()).toBe(false, notType.method)); 73 | }); 74 | }); 75 | }); 76 | }); -------------------------------------------------------------------------------- /spec/integration/function/_resources/boolean.scad: -------------------------------------------------------------------------------- 1 | function test() = true; -------------------------------------------------------------------------------- /spec/integration/function/_resources/inf.scad: -------------------------------------------------------------------------------- 1 | /* 2 | Value retrieved from: 3 | https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#Values_and_Data_Types 4 | */ 5 | function test() = 1e200 * 1e200; -------------------------------------------------------------------------------- /spec/integration/function/_resources/nan.scad: -------------------------------------------------------------------------------- 1 | /* 2 | Value retrieved from: 3 | https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#Values_and_Data_Types 4 | */ 5 | function test() = 0 / 0; -------------------------------------------------------------------------------- /spec/integration/function/_resources/number.scad: -------------------------------------------------------------------------------- 1 | function test() = 5; -------------------------------------------------------------------------------- /spec/integration/function/_resources/range.scad: -------------------------------------------------------------------------------- 1 | function test() = [0 : 10]; -------------------------------------------------------------------------------- /spec/integration/function/_resources/string.scad: -------------------------------------------------------------------------------- 1 | function test() = "result"; -------------------------------------------------------------------------------- /spec/integration/function/_resources/undef.scad: -------------------------------------------------------------------------------- 1 | function test() = undef; -------------------------------------------------------------------------------- /spec/integration/function/_resources/vector.scad: -------------------------------------------------------------------------------- 1 | function test() = [0, 4]; -------------------------------------------------------------------------------- /spec/integration/threeD/ThreeDModuleSpec.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const UnitTestSCAD = require('../../../src'); 4 | const FileUtils = require('../_utils/FileUtils'); 5 | 6 | const openSCADDirectory = path.join(__dirname, '_resources'); 7 | 8 | describe('ThreeDModuleSpec', () => { 9 | afterEach(() => FileUtils.checkClean()); 10 | 11 | describe('error', () => { 12 | it('should error on a bad .scad file', () => { 13 | expect(() => new UnitTestSCAD.ThreeDModule({ 14 | openSCADDirectory: path.join(__dirname, '..', '_resources'), 15 | use: ['garbage.scad'], 16 | })).toThrow(); 17 | }); 18 | }); 19 | 20 | describe('success', () => { 21 | const expectedVertices = [ 22 | [0, 4, 6], 23 | [5, 0, 6], 24 | [5, 4, 6], 25 | [0, 0, 6], 26 | [0, 0, 0], 27 | [5, 4, 0], 28 | [5, 0, 0], 29 | [0, 4, 0], 30 | ]; 31 | const expectedTriangles = [ 32 | [[0, 4, 6], [5, 0, 6], [5, 4, 6]], 33 | [[5, 0, 6], [0, 4, 6], [0, 0, 6]], 34 | [[0, 0, 0], [5, 4, 0], [5, 0, 0]], 35 | [[5, 4, 0], [0, 0, 0], [0, 4, 0]], 36 | [[0, 0, 0], [5, 0, 6], [0, 0, 6]], 37 | [[5, 0, 6], [0, 0, 0], [5, 0, 0]], 38 | [[5, 0, 6], [5, 4, 0], [5, 4, 6]], 39 | [[5, 4, 0], [5, 0, 6], [5, 0, 0]], 40 | [[5, 4, 0], [0, 4, 6], [5, 4, 6]], 41 | [[0, 4, 6], [5, 4, 0], [0, 4, 0]], 42 | [[0, 0, 0], [0, 4, 6], [0, 4, 0]], 43 | [[0, 4, 6], [0, 0, 0], [0, 0, 6]] 44 | ]; 45 | 46 | describe('include', () => { 47 | let testee; 48 | 49 | beforeEach(() => { 50 | testee = new UnitTestSCAD.ThreeDModule({ 51 | openSCADDirectory, 52 | include: ['cube.scad'], 53 | }); 54 | }); 55 | 56 | it('should have the correct height', () => expect(testee.height).toBe(4)); 57 | it('should have the correct width', () => expect(testee.width).toBe(5)); 58 | it('should have the correct depth', () => expect(testee.depth).toBe(6)); 59 | it('should have the correct vertices', () => expect(testee.vertices).toEqual(expectedVertices)); 60 | it('should have the correct triangles', () => expect(testee.triangles).toEqual(expectedTriangles)); 61 | }); 62 | 63 | describe('use', () => { 64 | let testee; 65 | 66 | beforeEach(() => { 67 | testee = new UnitTestSCAD.ThreeDModule({ 68 | openSCADDirectory, 69 | use: ['cube-module.scad'], 70 | testText: 'myCube([5, 4, 6]);' 71 | }); 72 | }); 73 | 74 | it('should have the correct height', () => expect(testee.height).toBe(4)); 75 | it('should have the correct width', () => expect(testee.width).toBe(5)); 76 | it('should have the correct depth', () => expect(testee.depth).toBe(6)); 77 | it('should have the correct vertices', () => expect(testee.vertices).toEqual(expectedVertices)); 78 | it('should have the correct triangles', () => expect(testee.triangles).toEqual(expectedTriangles)); 79 | }); 80 | 81 | describe('setUpText', () => { 82 | let testee; 83 | 84 | beforeEach(() => { 85 | testee = new UnitTestSCAD.ThreeDModule({ 86 | openSCADDirectory, 87 | setUpText: 'cube([5, 4, 6]);' 88 | }); 89 | }); 90 | 91 | it('should have the correct height', () => expect(testee.height).toBe(4)); 92 | it('should have the correct width', () => expect(testee.width).toBe(5)); 93 | it('should have the correct depth', () => expect(testee.depth).toBe(6)); 94 | it('should have the correct vertices', () => expect(testee.vertices).toEqual(expectedVertices)); 95 | it('should have the correct triangles', () => expect(testee.triangles).toEqual(expectedTriangles)); 96 | }); 97 | 98 | describe('testText', () => { 99 | let testee; 100 | 101 | beforeEach(() => { 102 | testee = new UnitTestSCAD.ThreeDModule({ 103 | openSCADDirectory, 104 | testText: 'cube([5, 4, 6]);' 105 | }); 106 | }); 107 | 108 | it('should have the correct height', () => expect(testee.height).toBe(4)); 109 | it('should have the correct width', () => expect(testee.width).toBe(5)); 110 | it('should have the correct depth', () => expect(testee.depth).toBe(6)); 111 | it('should have the correct vertices', () => expect(testee.vertices).toEqual(expectedVertices)); 112 | it('should have the correct triangles', () => expect(testee.triangles).toEqual(expectedTriangles)); 113 | }); 114 | }); 115 | }); -------------------------------------------------------------------------------- /spec/integration/threeD/_resources/cube-module.scad: -------------------------------------------------------------------------------- 1 | module myCube(dimensions) { 2 | cube(dimensions); 3 | } -------------------------------------------------------------------------------- /spec/integration/threeD/_resources/cube.scad: -------------------------------------------------------------------------------- 1 | cube([5, 4, 6]); -------------------------------------------------------------------------------- /spec/integration/twoD/TwoDModuleSpec.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const UnitTestSCAD = require('../../../src'); 4 | const FileUtils = require('../_utils/FileUtils'); 5 | 6 | const openSCADDirectory = path.join(__dirname, '_resources'); 7 | 8 | describe('TwoDModuleSpec', () => { 9 | afterEach(() => FileUtils.checkClean()); 10 | 11 | describe('error', () => { 12 | it('should error on a bad .scad file', () => { 13 | expect(() => new UnitTestSCAD.TwoDModule({ 14 | openSCADDirectory: path.join(__dirname, '..', '_resources'), 15 | use: ['garbage.scad'], 16 | })).toThrow(); 17 | }); 18 | }); 19 | 20 | describe('success', () => { 21 | const expectedVertices = [ 22 | [0, -0], 23 | [5, -0], 24 | [5, -4], 25 | [0, -4], 26 | ]; 27 | 28 | describe('include', () => { 29 | let testee; 30 | 31 | beforeEach(() => { 32 | testee = new UnitTestSCAD.TwoDModule({ 33 | openSCADDirectory, 34 | include: ['square.scad'], 35 | }); 36 | }); 37 | 38 | it('should have the correct height', () => expect(testee.height).toBe(4)); 39 | it('should have the correct width', () => expect(testee.width).toBe(5)); 40 | it('should have the correct vertices', () => expect(testee.vertices).toEqual(expectedVertices)); 41 | }); 42 | 43 | describe('use', () => { 44 | let testee; 45 | 46 | beforeEach(() => { 47 | testee = new UnitTestSCAD.TwoDModule({ 48 | openSCADDirectory, 49 | use: ['square-module.scad'], 50 | testText: 'mySquare([5, 4]);' 51 | }); 52 | }); 53 | 54 | it('should have the correct height', () => expect(testee.height).toBe(4)); 55 | it('should have the correct width', () => expect(testee.width).toBe(5)); 56 | it('should have the correct vertices', () => expect(testee.vertices).toEqual(expectedVertices)); 57 | }); 58 | 59 | describe('setUpText', () => { 60 | let testee; 61 | 62 | beforeEach(() => { 63 | testee = new UnitTestSCAD.TwoDModule({ 64 | openSCADDirectory, 65 | setUpText: 'square([5, 4]);' 66 | }); 67 | }); 68 | 69 | it('should have the correct height', () => expect(testee.height).toBe(4)); 70 | it('should have the correct width', () => expect(testee.width).toBe(5)); 71 | it('should have the correct vertices', () => expect(testee.vertices).toEqual(expectedVertices)); 72 | }); 73 | 74 | describe('testText', () => { 75 | let testee; 76 | 77 | beforeEach(() => { 78 | testee = new UnitTestSCAD.TwoDModule({ 79 | openSCADDirectory, 80 | testText: 'square([5, 4]);' 81 | }); 82 | }); 83 | 84 | it('should have the correct height', () => expect(testee.height).toBe(4)); 85 | it('should have the correct width', () => expect(testee.width).toBe(5)); 86 | it('should have the correct vertices', () => expect(testee.vertices).toEqual(expectedVertices)); 87 | }); 88 | }); 89 | }); -------------------------------------------------------------------------------- /spec/integration/twoD/_resources/square-module.scad: -------------------------------------------------------------------------------- 1 | module mySquare(dimensions) { 2 | square(dimensions); 3 | } -------------------------------------------------------------------------------- /spec/integration/twoD/_resources/square.scad: -------------------------------------------------------------------------------- 1 | square([5, 4]); -------------------------------------------------------------------------------- /spec/unit/_resources/function-output.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | OpenSCAD Model 5 | -------------------------------------------------------------------------------- /spec/unit/api/AbstractModuleSpec.js: -------------------------------------------------------------------------------- 1 | const proxyquire = require('proxyquire'); 2 | 3 | const mockAbstractParent = class {}; 4 | 5 | const AbstractModule = proxyquire('../../../src/api/AbstractModule', { 6 | './AbstractParent': mockAbstractParent 7 | }); 8 | 9 | function generateAbstractModule(vertices) { 10 | const abstractModule = new AbstractModule(); 11 | abstractModule.vertices = vertices; 12 | return abstractModule; 13 | } 14 | 15 | describe('AbstractModuleSpec', () => { 16 | describe('2d', () => { 17 | it('should be within bounds when equal', () => { 18 | const testee = generateAbstractModule([ 19 | [-1, -1], 20 | [1, 1] 21 | ]); 22 | 23 | const box = { 24 | min: [-1, -1], 25 | max: [1, 1] 26 | }; 27 | 28 | expect(testee.isWithinBoundingBox(box)).toBe(true, box); 29 | }); 30 | 31 | it('should be within bounds when all are within', () => { 32 | const testee = generateAbstractModule([ 33 | [-1, -1], 34 | [1, 1] 35 | ]); 36 | 37 | const box = { 38 | min: [-2, -2], 39 | max: [2, 2] 40 | }; 41 | 42 | expect(testee.isWithinBoundingBox(box)).toBe(true, box); 43 | }); 44 | 45 | it('should not be within bounds when \'x\' is smaller than minimum', () => { 46 | const testee = generateAbstractModule([ 47 | [-5, -1], 48 | [1, 1] 49 | ]); 50 | 51 | const box = { 52 | min: [-2, -2], 53 | max: [2, 2] 54 | }; 55 | 56 | expect(testee.isWithinBoundingBox(box)).toBe(false, box); 57 | }); 58 | 59 | it('should not be within bounds when \'x\' is greater than maximum', () => { 60 | const testee = generateAbstractModule([ 61 | [-1, -1], 62 | [5, 1] 63 | ]); 64 | 65 | const box = { 66 | min: [-2, -2], 67 | max: [2, 2] 68 | }; 69 | 70 | expect(testee.isWithinBoundingBox(box)).toBe(false, box); 71 | }); 72 | 73 | it('should not be within bounds when \'y\' is smaller than minimum', () => { 74 | const testee = generateAbstractModule([ 75 | [-1, -5], 76 | [1, 1] 77 | ]); 78 | 79 | const box = { 80 | min: [-2, -2], 81 | max: [2, 2] 82 | }; 83 | 84 | expect(testee.isWithinBoundingBox(box)).toBe(false, box); 85 | }); 86 | 87 | it('should not be within bounds when \'y\' is greater than maximum', () => { 88 | const testee = generateAbstractModule([ 89 | [-1, -1], 90 | [1, 5] 91 | ]); 92 | 93 | const box = { 94 | min: [-2, -2], 95 | max: [2, 2] 96 | }; 97 | 98 | expect(testee.isWithinBoundingBox(box)).toBe(false, box); 99 | }); 100 | }); 101 | 102 | describe('3d', () => { 103 | it('should be within bounds when equal', () => { 104 | const testee = generateAbstractModule([ 105 | [-1, -1, -1], 106 | [1, 1, 1] 107 | ]); 108 | 109 | const box = { 110 | min: [-1, -1, -1], 111 | max: [1, 1, 1] 112 | }; 113 | 114 | expect(testee.isWithinBoundingBox(box)).toBe(true, box); 115 | }); 116 | 117 | it('should be within bounds when all are within', () => { 118 | const testee = generateAbstractModule([ 119 | [-1, -1, -1], 120 | [1, 1, 1] 121 | ]); 122 | 123 | const box = { 124 | min: [-2, -2, -2], 125 | max: [2, 2, 2] 126 | }; 127 | 128 | expect(testee.isWithinBoundingBox(box)).toBe(true, box); 129 | }); 130 | 131 | it('should not be within bounds when \'x\' is smaller than minimum', () => { 132 | const testee = generateAbstractModule([ 133 | [-5, -1, -1], 134 | [1, 1, 1] 135 | ]); 136 | 137 | const box = { 138 | min: [-2, -2, -2], 139 | max: [2, 2, 2] 140 | }; 141 | 142 | expect(testee.isWithinBoundingBox(box)).toBe(false, box); 143 | }); 144 | 145 | it('should not be within bounds when \'x\' is greater than maximum', () => { 146 | const testee = generateAbstractModule([ 147 | [-1, -1, -1], 148 | [5, 1, 1] 149 | ]); 150 | 151 | const box = { 152 | min: [-2, -2, -2], 153 | max: [2, 2, 2] 154 | }; 155 | 156 | expect(testee.isWithinBoundingBox(box)).toBe(false, box); 157 | }); 158 | 159 | it('should not be within bounds when \'y\' is smaller than minimum', () => { 160 | const testee = generateAbstractModule([ 161 | [-1, -5, -1], 162 | [1, 1, 1] 163 | ]); 164 | 165 | const box = { 166 | min: [-2, -2, -2], 167 | max: [2, 2, 2] 168 | }; 169 | 170 | expect(testee.isWithinBoundingBox(box)).toBe(false, box); 171 | }); 172 | 173 | it('should not be within bounds when \'y\' is greater than maximum', () => { 174 | const testee = generateAbstractModule([ 175 | [-1, -1, -1], 176 | [1, 5, 1] 177 | ]); 178 | 179 | const box = { 180 | min: [-2, -2, -2], 181 | max: [2, 2, 2] 182 | }; 183 | 184 | expect(testee.isWithinBoundingBox(box)).toBe(false, box); 185 | }); 186 | 187 | it('should not be within bounds when \'z\' is smaller than minimum', () => { 188 | const testee = generateAbstractModule([ 189 | [-1, -1, -5], 190 | [1, 1, 1] 191 | ]); 192 | 193 | const box = { 194 | min: [-2, -2, -2], 195 | max: [2, 2, 2] 196 | }; 197 | 198 | expect(testee.isWithinBoundingBox(box)).toBe(false, box); 199 | }); 200 | 201 | it('should not be within bounds when \'z\' is greater than maximum', () => { 202 | const testee = generateAbstractModule([ 203 | [-1, -1, -1], 204 | [1, 1, 5] 205 | ]); 206 | 207 | const box = { 208 | min: [-2, -2, -2], 209 | max: [2, 2, 2] 210 | }; 211 | 212 | expect(testee.isWithinBoundingBox(box)).toBe(false, box); 213 | }); 214 | }); 215 | }); -------------------------------------------------------------------------------- /spec/unit/api/AbstractParentSpec.js: -------------------------------------------------------------------------------- 1 | const proxyquire = require('proxyquire'); 2 | 3 | const header = 'header'; 4 | const mockHeader = { 5 | getHeader: jasmine.createSpy('mockHeader.getHeader').and.returnValue(header) 6 | }; 7 | 8 | const output = 'output'; 9 | const mockFileType = { 10 | execute: jasmine.createSpy('mockFileType.execute').and.returnValue(output) 11 | }; 12 | 13 | const AbstractParent = proxyquire('../../../src/api/AbstractParent', { 14 | '../file/Header': mockHeader 15 | }); 16 | 17 | describe('AbstractParentSpec', () => { 18 | describe('sanitise', () => { 19 | 20 | it('should call with values given', () => { 21 | const openSCADDirectory = 'directory'; 22 | const use = ['a', 'b', 'c']; 23 | const include = ['x', 'y', 'z']; 24 | const setUpText = 'setUpText'; 25 | const testText = 'testText'; 26 | 27 | new AbstractParent({ 28 | openSCADDirectory, 29 | use, 30 | include, 31 | setUpText, 32 | testText 33 | }, mockFileType); 34 | 35 | expect(mockHeader.getHeader).toHaveBeenCalledWith(openSCADDirectory, use, include); 36 | expect(mockFileType.execute).toHaveBeenCalledWith(header, setUpText, testText); 37 | }); 38 | 39 | it('should use default values when not defined', () => { 40 | new AbstractParent({}, mockFileType); 41 | 42 | expect(mockHeader.getHeader).toHaveBeenCalledWith('', [], []); 43 | expect(mockFileType.execute).toHaveBeenCalledWith(header, '', ''); 44 | }); 45 | }); 46 | 47 | describe('output', () => { 48 | it('should get the output from file execution', () => { 49 | const testee = new AbstractParent({}, mockFileType); 50 | 51 | expect(testee.output).toBe(output); 52 | }); 53 | }); 54 | }); -------------------------------------------------------------------------------- /spec/unit/api/OpenSCADFunctionSpec.js: -------------------------------------------------------------------------------- 1 | const proxyquire = require('proxyquire'); 2 | 3 | const Types = require('../../../src/types/Types'); 4 | 5 | const output = 'output'; 6 | const types = [ 7 | { 8 | type: Types.BOOLEAN, 9 | method: 'isBoolean' 10 | }, { 11 | type: Types.INF, 12 | method: 'isInf' 13 | }, { 14 | type: Types.NAN, 15 | method: 'isNan' 16 | }, { 17 | type: Types.NUMBER, 18 | method: 'isNumber' 19 | }, { 20 | type: Types.RANGE, 21 | method: 'isRange' 22 | }, { 23 | type: Types.STRING, 24 | method: 'isString' 25 | }, { 26 | type: Types.UNDEF, 27 | method: 'isUndef' 28 | }, { 29 | type: Types.VECTOR, 30 | method: 'isVector' 31 | } 32 | ]; 33 | 34 | const mockFunctionFile = { 35 | execute: jasmine.createSpy('mockFunctionFile.execute').and.returnValue(output) 36 | }; 37 | 38 | const mockTypeConverter = { 39 | getType: jasmine.createSpy('mockTypeConverter.getType') 40 | }; 41 | 42 | const OpenSCADFunction = proxyquire('../../../src/api/OpenSCADFunction', { 43 | '../file/FunctionFile': mockFunctionFile, 44 | '../types/TypeConverter': mockTypeConverter, 45 | }); 46 | 47 | describe('OpenSCADFunctionSpec', () => { 48 | let testee; 49 | 50 | types.forEach(type => { 51 | describe(type.type, () => { 52 | beforeEach(() => { 53 | mockTypeConverter.getType.and.returnValue(type.type); 54 | testee = new OpenSCADFunction(); 55 | }); 56 | 57 | it('should get the type from TypeConverter', () => { 58 | expect(testee.type).toBe(type.type); 59 | expect(mockTypeConverter.getType).toHaveBeenCalledWith(output); 60 | }); 61 | 62 | 63 | it(`${type.method} should be true`, () => 64 | 65 | expect(testee[type.method]()).toBe(true, type.method)); 66 | 67 | types 68 | .filter(notType => notType !== type) 69 | .forEach(notType => { 70 | it(`${notType.method} should be false`, () => 71 | 72 | expect(testee[notType.method]()).toBe(false, notType.method)); 73 | }); 74 | }); 75 | }); 76 | }); -------------------------------------------------------------------------------- /spec/unit/api/ThreeDModuleSpec.js: -------------------------------------------------------------------------------- 1 | const {EOL} = require('os'); 2 | 3 | const proxyquire = require('proxyquire'); 4 | 5 | const output = `outer loop vertex${EOL}vertex 0 0 0${EOL}vertex 5 5 5${EOL}vertex 7.5 10.75 12${EOL}endloop${EOL}vertex 18.123 19 20${EOL}endfacet`; 6 | const mockThreeDModuleFile = { 7 | execute: jasmine.createSpy('mockThreeDModuleFile.execute').and.returnValue(output) 8 | }; 9 | 10 | const ThreeDModule = proxyquire('../../../src/api/ThreeDModule', { 11 | '../file/ThreeDModuleFile': mockThreeDModuleFile 12 | }); 13 | 14 | describe('ThreeDModuleSpec', () => { 15 | let testee; 16 | beforeEach(() => { 17 | testee = new ThreeDModule(); 18 | }); 19 | 20 | it('should get the vertices', () => expect(testee.vertices).toEqual([ 21 | [0, 0, 0], 22 | [5, 5, 5], 23 | [7.5, 10.75, 12], 24 | [18.123, 19, 20], 25 | ])); 26 | it('should have the correct width', () => expect(testee.width).toBe(18.123)); 27 | it('should have the correct height', () => expect(testee.height).toBe(19)); 28 | it('should have the correct depth', () => expect(testee.depth).toBe(20)); 29 | it('should have the correct triangles', () => expect(testee.triangles).toEqual([ 30 | [ 31 | [0, 0, 0], 32 | [5, 5, 5], 33 | [7.5, 10.75, 12] 34 | ] 35 | ])); 36 | }); -------------------------------------------------------------------------------- /spec/unit/api/TwoDModuleSpec.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs'); 3 | 4 | const proxyquire = require('proxyquire'); 5 | 6 | const output = fs.readFileSync(path.join(__dirname, '..', '_resources', 'function-output.svg'), 'utf-8'); 7 | const mockTwoDModuleFile = jasmine.createSpyObj('mockTwoDModuleFile', ['execute']); 8 | 9 | const TwoDModule = proxyquire('../../../src/api/TwoDModule', { 10 | '../file/TwoDModuleFile': mockTwoDModuleFile 11 | }); 12 | 13 | describe('TwoDModuleSpec', () => { 14 | describe('successful XML parse', () => { 15 | let testee; 16 | 17 | beforeEach(() => { 18 | mockTwoDModuleFile.execute.and.returnValue(output); 19 | testee = new TwoDModule(); 20 | }); 21 | 22 | it('should extract the height', () => expect(testee.height).toBe(6)); 23 | it('should extract the width', () => expect(testee.width).toBe(6)); 24 | it('should extract the vertices', () => expect(testee.vertices).toEqual([ 25 | [6, -6], 26 | [5, -6], 27 | [5, -5], 28 | [6, -5], 29 | [1, -1], 30 | [0, -1], 31 | [0, -0], 32 | [1, -0], 33 | ])); 34 | }); 35 | 36 | describe('error thrown on XML parse', () => { 37 | const error = 'error'; 38 | 39 | beforeEach(() => mockTwoDModuleFile.execute.and.throwError(error)); 40 | 41 | it('should throw an error when it tries to instantiate the module', () => { 42 | expect(() => new TwoDModule()).toThrowError(error); 43 | }); 44 | }); 45 | }); -------------------------------------------------------------------------------- /spec/unit/file/FileSpec.js: -------------------------------------------------------------------------------- 1 | const {EOL} = require('os'); 2 | 3 | const proxyquire = require('proxyquire'); 4 | 5 | const options = { 6 | header: 'header', 7 | setUpText: 'setUpText', 8 | testText: 'testText' 9 | }; 10 | 11 | // scadFile comes directly from File.js 12 | const scadFile = 'UnitTestSCAD_48967_TEMP_DELETE-ME_SCAD.scad'; 13 | 14 | const tempDirectory = 'temp'; 15 | const output = 'output'; 16 | const error = 'error'; 17 | 18 | let mockChildProcess, mockFs, File; 19 | 20 | describe('FileSpec', () => { 21 | beforeEach(() => { 22 | mockChildProcess = jasmine.createSpyObj('mockChildProcess', [ 23 | 'execSync' 24 | ]); 25 | 26 | mockFs = jasmine.createSpyObj('mockFs', [ 27 | 'writeFileSync', 28 | 'readFileSync', 29 | 'existsSync', 30 | 'unlinkSync' 31 | ]); 32 | 33 | File = proxyquire('../../../src/file/File', { 34 | 'child_process': mockChildProcess, 35 | 'fs': mockFs, 36 | }); 37 | }); 38 | 39 | describe('openscad executes successfully', () => { 40 | beforeEach(() => { 41 | mockFs.readFileSync.and.returnValue(output); 42 | mockChildProcess.execSync.and.returnValue({ 43 | toString: jasmine.createSpy() 44 | }); 45 | }); 46 | 47 | describe('and file exists', () => { 48 | beforeEach(() => mockFs.existsSync.and.returnValue(true)); 49 | 50 | it('should write the file, execute, clean up and return the output', () => { 51 | const output = File.execute(options, tempDirectory); 52 | 53 | expect(output).toBe(output); 54 | expect(mockChildProcess.execSync).toHaveBeenCalledWith(`openscad -o ${tempDirectory} ${scadFile}`); 55 | expect(mockFs.writeFileSync).toHaveBeenCalledWith(scadFile, `${options.header}${EOL}${options.setUpText}${EOL}${options.testText}`); 56 | expect(mockFs.readFileSync).toHaveBeenCalledWith(tempDirectory, 'utf-8'); 57 | expect(mockFs.existsSync).toHaveBeenCalledWith(tempDirectory); 58 | expect(mockFs.unlinkSync).toHaveBeenCalledWith(tempDirectory); 59 | expect(mockFs.existsSync).toHaveBeenCalledWith(scadFile); 60 | expect(mockFs.unlinkSync).toHaveBeenCalledWith(scadFile); 61 | }); 62 | }); 63 | 64 | describe('and file does not exist', () => { 65 | beforeEach(() => mockFs.existsSync.and.returnValue(false)); 66 | 67 | it('should write the file, execute, NOT clean up and return the output', () => { 68 | const output = File.execute(options, tempDirectory); 69 | 70 | expect(output).toBe(output); 71 | expect(mockChildProcess.execSync).toHaveBeenCalledWith(`openscad -o ${tempDirectory} ${scadFile}`); 72 | expect(mockFs.writeFileSync).toHaveBeenCalledWith(scadFile, `${options.header}${EOL}${options.setUpText}${EOL}${options.testText}`); 73 | expect(mockFs.readFileSync).toHaveBeenCalledWith(tempDirectory, 'utf-8'); 74 | expect(mockFs.existsSync).toHaveBeenCalledWith(tempDirectory); 75 | expect(mockFs.existsSync).toHaveBeenCalledWith(scadFile); 76 | expect(mockFs.unlinkSync).not.toHaveBeenCalled(); 77 | }); 78 | }); 79 | }); 80 | 81 | describe('openscad fails to execute', () => { 82 | beforeEach(() => mockChildProcess.execSync.and.throwError(error)); 83 | 84 | describe('and file exists', () => { 85 | beforeEach(() => mockFs.existsSync.and.returnValue(true)); 86 | 87 | it('should clean up and throw error', () => { 88 | expect(() => File.execute(options, tempDirectory)).toThrowError(error); 89 | expect(mockFs.existsSync).toHaveBeenCalledWith(tempDirectory); 90 | expect(mockFs.unlinkSync).toHaveBeenCalledWith(tempDirectory); 91 | expect(mockFs.existsSync).toHaveBeenCalledWith(scadFile); 92 | expect(mockFs.unlinkSync).toHaveBeenCalledWith(scadFile); 93 | }); 94 | }); 95 | 96 | describe('and file does not exist', () => { 97 | beforeEach(() => mockFs.existsSync.and.returnValue(false)); 98 | 99 | it('should clean up and throw error', () => { 100 | expect(() => File.execute(options, tempDirectory)).toThrowError(error); 101 | expect(mockFs.existsSync).toHaveBeenCalledWith(tempDirectory); 102 | expect(mockFs.existsSync).toHaveBeenCalledWith(scadFile); 103 | expect(mockFs.unlinkSync).not.toHaveBeenCalled(); 104 | }); 105 | }); 106 | }); 107 | }); -------------------------------------------------------------------------------- /spec/unit/file/FunctionFileSpec.js: -------------------------------------------------------------------------------- 1 | const {EOL} = require('os'); 2 | 3 | const proxyquire = require('proxyquire'); 4 | 5 | // copied from FunctionFile.js 6 | const stlFile = 'UnitTestSCAD_48967_TEMP_DELETE-ME_FUNCTION.stl'; 7 | 8 | const startMarker = '"UnitTestSCAD __start_marker__"'; 9 | const endMarker = '"UnitTestSCAD __end_marker__"'; 10 | const failurePrevention = 'cube(1);'; 11 | 12 | const header = 'header'; 13 | const setUpText = 'setUpText'; 14 | const testText = 'testText'; 15 | 16 | const wrappedTestText = [ 17 | `echo(${startMarker});`, 18 | `echo(${testText});`, 19 | `echo(${endMarker});`, 20 | failurePrevention 21 | ].join(EOL); 22 | 23 | const mockFile = { 24 | execute: jasmine.createSpy('mockFile.execute').and.returnValue({ 25 | out: `ECHO: ${startMarker}${EOL}ECHO: Poop${EOL}ECHO: Boop${EOL}ECHO: Scoop${EOL}ECHO: ${endMarker}` 26 | }) 27 | }; 28 | 29 | const FunctionFile = proxyquire('../../../src/file/FunctionFile', { 30 | './File': mockFile 31 | }); 32 | 33 | describe('FunctionFileSpec', () => { 34 | it('should wrap and unwrap the text', () => { 35 | const output = FunctionFile.execute(header, setUpText, testText); 36 | 37 | // Idk why but `.toHaveBeenCalledWith()` really didn't like `wrappedTestText`'s content 38 | expect(mockFile.execute.calls.mostRecent().args[0].header).toBe(header); 39 | expect(mockFile.execute.calls.mostRecent().args[0].setUpText).toBe(setUpText); 40 | expect(mockFile.execute.calls.mostRecent().args[0].testText).toBe(wrappedTestText); 41 | expect(mockFile.execute.calls.mostRecent().args[1]).toBe(stlFile); 42 | 43 | expect(output).toBe(`Poop${EOL}Boop${EOL}Scoop`); 44 | }); 45 | 46 | it('should sanitise wrap and unwrap the text', () => { 47 | const output = FunctionFile.execute(header, setUpText, testText + ';'); 48 | 49 | expect(mockFile.execute.calls.mostRecent().args[0].header).toBe(header); 50 | expect(mockFile.execute.calls.mostRecent().args[0].setUpText).toBe(setUpText); 51 | expect(mockFile.execute.calls.mostRecent().args[0].testText).toBe(wrappedTestText); 52 | expect(mockFile.execute.calls.mostRecent().args[1]).toBe(stlFile); 53 | 54 | expect(output).toBe(`Poop${EOL}Boop${EOL}Scoop`); 55 | }); 56 | }); -------------------------------------------------------------------------------- /spec/unit/file/HeaderSpec.js: -------------------------------------------------------------------------------- 1 | const {EOL} = require('os'); 2 | 3 | const {getHeader} = require('../../../src/file/Header'); 4 | 5 | const mocks = ['a', 'b', 'c']; 6 | const uses = mocks.map(mock => `uses-${mock}`); 7 | const includes = mocks.map(mock => `includes-${mock}`); 8 | const directory = 'mockDirectory'; 9 | 10 | describe('HeaderSpec', () => { 11 | describe('getHeader', () => { 12 | describe('use', () => { 13 | it('should generate uses', () => { 14 | const header = getHeader('', uses, []); 15 | 16 | expect(header).toBe([ 17 | 'use ;', 18 | 'use ;', 19 | 'use ;', 20 | EOL, 21 | ].join(EOL)); 22 | }); 23 | 24 | it('should generate uses with route', () => { 25 | const header = getHeader(directory, uses, []); 26 | 27 | expect(header).toBe([ 28 | 'use ;', 29 | 'use ;', 30 | 'use ;', 31 | EOL, 32 | ].join(EOL)); 33 | }); 34 | }); 35 | 36 | describe('include', () => { 37 | it('should generate includes', () => { 38 | const header = getHeader('', [], includes); 39 | 40 | expect(header).toBe([ 41 | 'include ;', 42 | 'include ;', 43 | 'include ;', 44 | EOL, 45 | ].join(EOL)); 46 | }); 47 | 48 | it('should generate includes with route', () => { 49 | const header = getHeader(directory, [], includes); 50 | 51 | expect(header).toBe([ 52 | 'include ;', 53 | 'include ;', 54 | 'include ;', 55 | EOL, 56 | ].join(EOL)); 57 | }); 58 | }); 59 | 60 | describe('use and include', () => { 61 | it('should generate uses and includes', () => { 62 | const header = getHeader('', uses, includes); 63 | 64 | expect(header).toBe([ 65 | 'use ;', 66 | 'use ;', 67 | 'use ;', 68 | 'include ;', 69 | 'include ;', 70 | 'include ;', 71 | EOL, 72 | ].join(EOL)); 73 | }); 74 | 75 | it('should generate uses and includes with route', () => { 76 | const header = getHeader(directory, uses, includes); 77 | 78 | expect(header).toBe([ 79 | 'use ;', 80 | 'use ;', 81 | 'use ;', 82 | 'include ;', 83 | 'include ;', 84 | 'include ;', 85 | EOL, 86 | ].join(EOL)); 87 | }); 88 | }); 89 | }); 90 | 91 | }); 92 | -------------------------------------------------------------------------------- /spec/unit/file/ThreeDModuleFileSpec.js: -------------------------------------------------------------------------------- 1 | const proxyquire = require('proxyquire'); 2 | 3 | // Copied from ThreeDModuleFile.js 4 | const stlFile = 'UnitTestSCAD_48967_TEMP_DELETE-ME_THREE_D.stl'; 5 | 6 | const header = 'header'; 7 | const setUpText = 'setUpText'; 8 | const testText = 'testText'; 9 | 10 | const file = 'file'; 11 | const output = {file}; 12 | const mockFile = { 13 | execute: jasmine.createSpy('mockFile.execute').and.returnValue(output) 14 | }; 15 | 16 | const ThreeDModuleFile = proxyquire('../../../src/file/ThreeDModuleFile', { 17 | './File': mockFile 18 | }); 19 | 20 | describe('ThreeDModuleFileSpec', () => { 21 | it('should call through to File.execute', () => { 22 | const result = ThreeDModuleFile.execute(header, setUpText, testText); 23 | 24 | expect(result).toBe(file); 25 | expect(mockFile.execute).toHaveBeenCalledWith({ 26 | header, 27 | setUpText, 28 | testText, 29 | }, stlFile); 30 | }); 31 | }); -------------------------------------------------------------------------------- /spec/unit/file/TwoDModuleFileSpec.js: -------------------------------------------------------------------------------- 1 | const proxyquire = require('proxyquire'); 2 | 3 | // Copied from TwoDModuleFile.js 4 | const svgFile = 'UnitTestSCAD_48967_TEMP_DELETE-ME_TWO_D.svg'; 5 | 6 | const header = 'header'; 7 | const setUpText = 'setUpText'; 8 | const testText = 'testText'; 9 | 10 | const file = 'file'; 11 | const output = {file}; 12 | const mockFile = { 13 | execute: jasmine.createSpy('mockFile.execute').and.returnValue(output) 14 | }; 15 | 16 | const TwoDModuleFile = proxyquire('../../../src/file/TwoDModuleFile', { 17 | './File': mockFile 18 | }); 19 | 20 | describe('TwoDModuleFileSpec', () => { 21 | it('should call through to File.execute', () => { 22 | const result = TwoDModuleFile.execute(header, setUpText, testText); 23 | 24 | expect(result).toBe(file); 25 | expect(mockFile.execute).toHaveBeenCalledWith({ 26 | header, 27 | setUpText, 28 | testText, 29 | }, svgFile); 30 | }); 31 | }); -------------------------------------------------------------------------------- /spec/unit/indexSpec.js: -------------------------------------------------------------------------------- 1 | const index = require('../../src/index'); 2 | 3 | const OpenSCADFunction = require('../../src/api/OpenSCADFunction'); 4 | const ThreeDModule = require('../../src/api/ThreeDModule'); 5 | const TwoDModule = require('../../src/api/TwoDModule'); 6 | const Types = require('../../src/types/Types'); 7 | 8 | describe('indexSpec', () => { 9 | it('should have OpenSCADFunction', () => expect(index.Function).toBe(OpenSCADFunction)); 10 | it('should have ThreeDModule', () => expect(index.ThreeDModule).toBe(ThreeDModule)); 11 | it('should have TwoDModule', () => expect(index.TwoDModule).toBe(TwoDModule)); 12 | it('should have Types', () => expect(index.Types).toBe(Types)); 13 | }); -------------------------------------------------------------------------------- /spec/unit/types/TypeConverterSpec.js: -------------------------------------------------------------------------------- 1 | const TypeConverter = require('../../../src/types/TypeConverter'); 2 | const Types = require('../../../src/types/Types'); 3 | 4 | const booleans = ['true', 'false']; 5 | const inf = 'inf'; 6 | const nan = 'nan'; 7 | const numbers = ['1', '5', '10000', '1.34', '67.56']; 8 | const ranges = [ 9 | '[0:1]', 10 | '[120:342]', 11 | '[27809784:2348992]', 12 | '[0 : 1 : 10]' 13 | ]; 14 | const strings = [ 15 | '"Hello"', 16 | '"World"', 17 | '"Foo"', 18 | '"Bar"' 19 | ]; 20 | const undef = 'undef'; 21 | const vectors = [ 22 | '[0,1]', 23 | '[120,342]', 24 | '[27809784,2348992]' 25 | ]; 26 | 27 | const badValues = [ 28 | 'not', 29 | 'a', 30 | 'valid', 31 | 'value' 32 | ]; 33 | 34 | describe('TypeConverterSpec', () => { 35 | describe('bad values', () => { 36 | badValues.forEach(badValue => { 37 | it(`getType should be undefined for ${badValue}`, () => { 38 | expect(TypeConverter.getType(badValue)).toBe(undefined); 39 | }); 40 | }); 41 | }); 42 | 43 | describe('boolean', () => { 44 | booleans.forEach(bool => { 45 | it(`getType should be type 'boolean' for ${bool}`, () => { 46 | expect(TypeConverter.getType(bool)).toBe(Types.BOOLEAN); 47 | }); 48 | }); 49 | }); 50 | 51 | describe('inf', () => { 52 | it('getType should be type \'inf\' for \'inf\'', () => { 53 | expect(TypeConverter.getType(inf)).toBe(Types.INF); 54 | }); 55 | }); 56 | 57 | describe('nan', () => { 58 | it('getType should be type \'nan\' for \'nan\'', () => { 59 | expect(TypeConverter.getType(nan)).toBe(Types.NAN); 60 | }); 61 | }); 62 | 63 | describe('number', () => { 64 | numbers.forEach(number => { 65 | it(`getType should be type 'number' for ${number}`, () => { 66 | expect(TypeConverter.getType(number)).toBe(Types.NUMBER); 67 | }); 68 | }); 69 | }); 70 | 71 | describe('range', () => { 72 | ranges.forEach(range => { 73 | it(`getType should be type 'boolean' for ${range}`, () => { 74 | expect(TypeConverter.getType(range)).toBe(Types.RANGE); 75 | }); 76 | }); 77 | }); 78 | 79 | describe('string', () => { 80 | strings.forEach(string => { 81 | it(`getType should be type 'boolean' for ${string}`, () => { 82 | expect(TypeConverter.getType(string)).toBe(Types.STRING); 83 | }); 84 | }); 85 | }); 86 | 87 | describe('undef', () => { 88 | it('getType should be type \'undef\' for \'undef\'', () => { 89 | expect(TypeConverter.getType(undef)).toBe(Types.UNDEF); 90 | }); 91 | }); 92 | 93 | describe('vector', () => { 94 | vectors.forEach(vector => { 95 | it(`getType should be type 'vector' for ${vector}`, () => { 96 | expect(TypeConverter.getType(vector)).toBe(Types.VECTOR); 97 | }); 98 | }); 99 | }); 100 | }); -------------------------------------------------------------------------------- /spec/unit/types/TypesSpec.js: -------------------------------------------------------------------------------- 1 | const Types = require('../../../src/types/Types'); 2 | 3 | describe('TypesSpec', () => { 4 | it('should have BOOLEAN', () => expect(Types.BOOLEAN).toBe('boolean')); 5 | it('should have INF', () => expect(Types.INF).toBe('inf')); 6 | it('should have NAN', () => expect(Types.NAN).toBe('nan')); 7 | it('should have NUMBER', () => expect(Types.NUMBER).toBe('number')); 8 | it('should have RANGE', () => expect(Types.RANGE).toBe('range')); 9 | it('should have STRING', () => expect(Types.STRING).toBe('string')); 10 | it('should have UNDEF', () => expect(Types.UNDEF).toBe('undef')); 11 | it('should have VECTOR', () => expect(Types.VECTOR).toBe('vector')); 12 | }); -------------------------------------------------------------------------------- /src/api/AbstractModule.js: -------------------------------------------------------------------------------- 1 | const AbstractParent = require('./AbstractParent'); 2 | 3 | function isCoordinateWithinBounds(coordinate, min, max) { 4 | return coordinate >= min && coordinate <= max; 5 | } 6 | 7 | module.exports = class extends AbstractParent { 8 | constructor(options, file) { 9 | super(options, file); 10 | } 11 | 12 | /** 13 | * @typedef {object} BoundingBox A box in 2D/3D space. 14 | * @property {Vertex} min A 2D/3D vertex which defines the 'minimum' co-ordinates. This is the corner of the box with the lowest x, y and optional z co-ordinate. 15 | * @property {Vertex} max A 2D/3D vertex which defines the 'maximum' co-ordinates. This is the corner of the box with the highest x, y and optional z co-ordinate. 16 | */ 17 | 18 | isWithinBoundingBox(boundingBox) { 19 | const failingVertices = this.vertices.reduce((failingCounter, vertex) => { 20 | return failingCounter + vertex.reduce((accumulator, coordinate, index) => { 21 | return isCoordinateWithinBounds(coordinate, boundingBox.min[index], boundingBox.max[index]) ? accumulator : accumulator + 1; 22 | }, 0); 23 | }, 0); 24 | 25 | return failingVertices === 0; 26 | } 27 | }; -------------------------------------------------------------------------------- /src/api/AbstractParent.js: -------------------------------------------------------------------------------- 1 | const {getHeader} = require('../file/Header'); 2 | 3 | function valueOrDefault(object, property, defaultValue) { 4 | return (object !== undefined && object[property] !== undefined) ? object[property] : defaultValue; 5 | } 6 | 7 | function sanitise(options) { 8 | return { 9 | openSCADDirectory: valueOrDefault(options, 'openSCADDirectory', ''), 10 | use: valueOrDefault(options, 'use', []), 11 | include: valueOrDefault(options, 'include', []), 12 | setUpText: valueOrDefault(options, 'setUpText', ''), 13 | testText: valueOrDefault(options, 'testText', ''), 14 | }; 15 | } 16 | 17 | /** 18 | * @typedef {object} Options Key/value pair of options to configure the execution of an OpenSCAD test. 19 | * @property {String} openSCADDirectory The prefix to prepend to all uses/includes. 20 | * @property {String[]} use List of .scad files to import as 'use'. 21 | * @property {String[]} include List of .scad files to import as 'include'. 22 | * @property {String} setUpText Any required OpenSCAD code to set up the test. 23 | * @property {String} testText The OpenSCAD code to be tested and asserted on. 24 | */ 25 | 26 | /** 27 | * @typedef {number[]} Vertex A 2/3 length co-ordinate representing a point in 2D/3D space. 28 | */ 29 | 30 | module.exports = class { 31 | constructor(dirtyOptions, fileType) { 32 | const options = sanitise(dirtyOptions); 33 | const header = getHeader(options.openSCADDirectory, options.use, options.include); 34 | this.output = fileType.execute(header, options.setUpText, options.testText); 35 | } 36 | }; -------------------------------------------------------------------------------- /src/api/OpenSCADFunction.js: -------------------------------------------------------------------------------- 1 | const AbstractParent = require('./AbstractParent'); 2 | const FunctionFile = require('../file/FunctionFile'); 3 | const TypeConverter = require('../types/TypeConverter'); 4 | const Types = require('../types/Types'); 5 | 6 | /** @class */ 7 | class Function extends AbstractParent { 8 | /** 9 | * @param {Options} options 10 | */ 11 | constructor(options) { 12 | super(options, FunctionFile); 13 | /** 14 | * @memberof Function 15 | * @instance 16 | * @member {string} output The extracted output from execution of the .scad file. 17 | */ 18 | /** 19 | * @memberof Function 20 | * @instance 21 | * @member {Type} type The detected type of the value retrieved from the OpenSCAD function. 22 | */ 23 | this.type = TypeConverter.getType(this.output); 24 | } 25 | 26 | /** 27 | * Returns true if this type is of type {@link OpenSCADBoolean}. 28 | * @returns {boolean} True if this type is of type {@link OpenSCADBoolean}. 29 | */ 30 | isBoolean() { 31 | return this.type === Types.BOOLEAN; 32 | } 33 | 34 | /** 35 | * Returns true if this type is of type {@link OpenSCADInfinity}. 36 | * @returns {boolean} True if this type is of type {@link OpenSCADInfinity}. 37 | */ 38 | isInf() { 39 | return this.type === Types.INF; 40 | } 41 | 42 | /** 43 | * Returns true if this type is of type {@link OpenSCADNaN}. 44 | * @returns {boolean} True if this type is of type {@link OpenSCADNaN}. 45 | */ 46 | isNan() { 47 | return this.type === Types.NAN; 48 | } 49 | 50 | /** 51 | * Returns true if this type is of type {@link OpenSCADNumber}. 52 | * @returns {boolean} True if this type is of type {@link OpenSCADNumber}. 53 | */ 54 | isNumber() { 55 | return this.type === Types.NUMBER; 56 | } 57 | 58 | /** 59 | * Returns true if this type is of type {@link OpenSCADRange}. 60 | * @returns {boolean} True if this type is of type {@link OpenSCADBoolean}. 61 | */ 62 | isRange() { 63 | return this.type === Types.RANGE; 64 | } 65 | 66 | /** 67 | * Returns true if this type is of type {@link OpenSCADString}. 68 | * @returns {boolean} True if this type is of type {@link OpenSCADString}. 69 | */ 70 | isString() { 71 | return this.type === Types.STRING; 72 | } 73 | 74 | /** 75 | * Returns true if this type is of type {@link OpenSCADUndefined}. 76 | * @returns {boolean} True if this type is of type {@link OpenSCADUndefined}. 77 | */ 78 | isUndef() { 79 | return this.type === Types.UNDEF; 80 | } 81 | 82 | /** 83 | * Returns true if this type is of type {@link OpenSCADVector}. 84 | * @returns {boolean} True if this type is of type {@link OpenSCADVector}. 85 | */ 86 | isVector() { 87 | return this.type === Types.VECTOR; 88 | } 89 | } 90 | 91 | module.exports = Function; -------------------------------------------------------------------------------- /src/api/ThreeDModule.js: -------------------------------------------------------------------------------- 1 | const {EOL} = require('os'); 2 | 3 | const AbstractModule = require('./AbstractModule'); 4 | const ThreeDModuleFile = require('../file/ThreeDModuleFile'); 5 | 6 | function getDimensionSize(vertices, index) { 7 | const range = vertices.reduce((accumulator, vertex) => { 8 | return { 9 | min: vertex[index] < accumulator.min ? vertex[index] : accumulator.min, 10 | max: vertex[index] > accumulator.max ? vertex[index] : accumulator.max, 11 | }; 12 | }, { 13 | min: Number.POSITIVE_INFINITY, 14 | max: Number.NEGATIVE_INFINITY 15 | }); 16 | 17 | return range.max - range.min; 18 | } 19 | 20 | function getVertex(content) { 21 | return content 22 | .split(' ') 23 | // Last three elements should be the co-ordinates, as a string 24 | .slice(-3) 25 | .map(vertex => parseFloat(vertex, 10)); 26 | } 27 | 28 | function getVertices(contents) { 29 | const vertexRegex = new RegExp(/vertex([ ][0-9]+[.]*[0-9]*){3}/, 'gm'); 30 | 31 | return contents 32 | .match(vertexRegex) 33 | .filter((value, index, self) => self.indexOf(value) === index) 34 | .map(vertexString => getVertex(vertexString)); 35 | } 36 | 37 | function getTriangles(contents) { 38 | const triangleRegex = new RegExp(/outer loop[\s\S]+?endloop/, 'g'); 39 | 40 | return contents 41 | .match(triangleRegex) 42 | .map(triangleString => triangleString.split(EOL)) 43 | .map(triangleStrings => triangleStrings.splice(1, 3)) 44 | .map(verticesOfTriangleStrings => { 45 | return verticesOfTriangleStrings.map(vertexString => getVertex(vertexString)); 46 | }); 47 | } 48 | 49 | /** @class */ 50 | class ThreeDModule extends AbstractModule { 51 | /** @param {Options} options */ 52 | constructor(options) { 53 | super(options, ThreeDModuleFile); 54 | /** 55 | * @memberof ThreeDModule 56 | * @instance 57 | * @member {string} output The extracted output from execution of the .scad file. 58 | */ 59 | 60 | /** 61 | * @memberof ThreeDModule 62 | * @instance 63 | * @function 64 | * @name isWithinBoundingBox 65 | * @param boundingBox {BoundingBox} The 3D box which the model should fit inside. It is considered 'within' if any coordinate is equal to, or within the box. 66 | * @returns {boolean} True if the model fits within the bounding box. 67 | */ 68 | 69 | /** 70 | * @memberof ThreeDModule 71 | * @instance 72 | * @member {Vertex[]} vertices A list of 3D vertices returned from the .scad file execution. 73 | */ 74 | this.vertices = getVertices(this.output); 75 | 76 | /** 77 | * @memberof ThreeDModule 78 | * @instance 79 | * @member {number} width The width of the model. 80 | */ 81 | this.width = getDimensionSize(this.vertices, 0); 82 | 83 | /** 84 | * @memberof ThreeDModule 85 | * @instance 86 | * @member {number} height The height of the model. 87 | */ 88 | this.height = getDimensionSize(this.vertices, 1); 89 | 90 | /** 91 | * @memberof ThreeDModule 92 | * @instance 93 | * @member {number} depth The depth of the model. 94 | */ 95 | this.depth = getDimensionSize(this.vertices, 2); 96 | 97 | /** 98 | * @typedef {Vertex[]} Triangle An array of three 3D vertices which describe a triangle. See {@link https://en.wikipedia.org/wiki/Triangle_mesh}. 99 | */ 100 | 101 | /** 102 | * @memberof ThreeDModule 103 | * @instance 104 | * @member {Triangle[]} triangles The triangles which make up the model. See {@link https://en.wikipedia.org/wiki/Triangle_mesh}. 105 | */ 106 | this.triangles = getTriangles(this.output); 107 | } 108 | } 109 | 110 | module.exports = ThreeDModule; -------------------------------------------------------------------------------- /src/api/TwoDModule.js: -------------------------------------------------------------------------------- 1 | const xml2js = require('xml2js'); 2 | 3 | const AbstractModule = require('./AbstractModule'); 4 | const TwoDModuleFile = require('../file/TwoDModuleFile'); 5 | 6 | function getVertices(parsedOutput) { 7 | return parsedOutput.path 8 | .reduce((previousValue, currentValue) => { 9 | return previousValue.concat(currentValue.$.d.match(/(-*\d+,-*\d+)/g)); 10 | }, []) 11 | .map(value => value 12 | .split(',') 13 | .map(point => parseFloat(point)) 14 | ); 15 | } 16 | 17 | /** @class */ 18 | class TwoDModule extends AbstractModule { 19 | /** 20 | * @param {Options} options 21 | */ 22 | constructor(options) { 23 | super(options, TwoDModuleFile); 24 | 25 | /** 26 | * @memberof TwoDModule 27 | * @instance 28 | * @member {string} output The extracted output from execution of the .scad file. 29 | */ 30 | 31 | /** 32 | * @memberof TwoDModule 33 | * @instance 34 | * @function 35 | * @name isWithinBoundingBox 36 | * @param boundingBox {BoundingBox} The 2D box which the model should fit inside. It is considered 'within' if any coordinate is equal to, or within the box. 37 | * @returns {boolean} True if the model fits within the bounding box. 38 | */ 39 | 40 | xml2js.parseString(this.output, (error, result) => { 41 | if(error) { 42 | throw new Error(error); 43 | } else { 44 | /** 45 | * @memberof TwoDModule 46 | * @instance 47 | * @member {Vertex[]} vertices A list of 2D vertices returned from the .scad file execution. 48 | */ 49 | this.vertices = getVertices(result.svg); 50 | 51 | /** 52 | * @memberof TwoDModule 53 | * @instance 54 | * @member {number} height The height of the model. 55 | */ 56 | this.height = parseInt(result.svg.$.height, 10); 57 | /** 58 | * @memberof TwoDModule 59 | * @instance 60 | * @member {number} width The width of the model. 61 | */ 62 | this.width = parseInt(result.svg.$.width, 10); 63 | } 64 | }); 65 | } 66 | } 67 | 68 | module.exports = TwoDModule; -------------------------------------------------------------------------------- /src/file/File.js: -------------------------------------------------------------------------------- 1 | const {EOL} = require('os'); 2 | const fs = require('fs'); 3 | const {execSync} = require('child_process'); 4 | 5 | const scadFile = 'UnitTestSCAD_48967_TEMP_DELETE-ME_SCAD.scad'; 6 | 7 | function writeSCADFile(header, setUpText, testText) { 8 | const contents = `${header}${EOL}${setUpText}${EOL}${testText}`; 9 | fs.writeFileSync(scadFile, contents); 10 | } 11 | 12 | function executeOpenSCAD(tempFile) { 13 | const command = `openscad -o ${tempFile} ${scadFile}`; 14 | const out = execSync(command).toString(); 15 | const file = fs.readFileSync(tempFile, 'utf-8'); 16 | return { 17 | out, 18 | file, 19 | }; 20 | } 21 | 22 | function safeUnlink(file) { 23 | if(fs.existsSync(file)) { 24 | fs.unlinkSync(file); 25 | } 26 | } 27 | 28 | module.exports = { 29 | execute(options, tempOutput) { 30 | writeSCADFile(options.header, options.setUpText, options.testText); 31 | try { 32 | return executeOpenSCAD(tempOutput); 33 | } catch(error) { 34 | throw error; 35 | } finally { 36 | safeUnlink(tempOutput); 37 | safeUnlink(scadFile); 38 | } 39 | } 40 | }; -------------------------------------------------------------------------------- /src/file/FunctionFile.js: -------------------------------------------------------------------------------- 1 | const {EOL} = require('os'); 2 | 3 | const File = require('./File'); 4 | 5 | const stlFile = 'UnitTestSCAD_48967_TEMP_DELETE-ME_FUNCTION.stl'; 6 | 7 | const startMarker = '"UnitTestSCAD __start_marker__"'; 8 | const endMarker = '"UnitTestSCAD __end_marker__"'; 9 | const failurePrevention = 'cube(1);'; 10 | 11 | function removeTrailingSemicolon(text) { 12 | if(text.endsWith(';')) { 13 | return text.slice(0, -1); 14 | } else { 15 | return text; 16 | } 17 | } 18 | 19 | function wrapWithMarkers(text) { 20 | return [ 21 | `echo(${startMarker});`, 22 | `echo(${removeTrailingSemicolon(text)});`, 23 | `echo(${endMarker});`, 24 | failurePrevention 25 | ].join(EOL); 26 | } 27 | 28 | function extractText(text) { 29 | const ECHO = 'ECHO: '; 30 | const content = text.split(EOL); 31 | 32 | return content 33 | .slice( 34 | content.indexOf(`${ECHO}${startMarker}`) + 1, 35 | content.indexOf(`${ECHO}${endMarker}`) 36 | ) 37 | .map(line => line.slice(ECHO.length)) 38 | .join(EOL); 39 | } 40 | 41 | module.exports = { 42 | execute(header, setUpText, testText) { 43 | return extractText(File.execute({ 44 | header, 45 | setUpText, 46 | testText: wrapWithMarkers(testText), 47 | }, stlFile).out); 48 | } 49 | }; -------------------------------------------------------------------------------- /src/file/Header.js: -------------------------------------------------------------------------------- 1 | const {EOL} = require('os'); 2 | 3 | function wrapInImport(prefix, directory, fileName) { 4 | const route = directory !== '' ? `${directory}/` : ''; 5 | return `${prefix} <${route}${fileName}>;${EOL}`; 6 | } 7 | 8 | function getImports(imports, prefix, directory) { 9 | return imports.reduce((accumulator, i) => `${accumulator}${wrapInImport(prefix, directory, i)}`, ''); 10 | } 11 | 12 | function getUses(imports, directory) { 13 | return getImports(imports, 'use', directory); 14 | } 15 | 16 | function getIncludes(imports, directory) { 17 | return getImports(imports, 'include', directory); 18 | } 19 | 20 | module.exports = { 21 | getHeader(directory, uses, includes) { 22 | return `${getUses(uses, directory)}${getIncludes(includes, directory)}${EOL}`; 23 | } 24 | }; -------------------------------------------------------------------------------- /src/file/ThreeDModuleFile.js: -------------------------------------------------------------------------------- 1 | const File = require('./File'); 2 | 3 | const stlFile = 'UnitTestSCAD_48967_TEMP_DELETE-ME_THREE_D.stl'; 4 | 5 | module.exports = { 6 | execute(header, setUpText, testText) { 7 | return File.execute({ 8 | header, 9 | setUpText, 10 | testText, 11 | }, stlFile).file; 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /src/file/TwoDModuleFile.js: -------------------------------------------------------------------------------- 1 | const File = require('./File'); 2 | 3 | const svgFile = 'UnitTestSCAD_48967_TEMP_DELETE-ME_TWO_D.svg'; 4 | 5 | module.exports = { 6 | execute(header, setUpText, testText) { 7 | return File.execute({ 8 | header, 9 | setUpText, 10 | testText, 11 | }, svgFile).file; 12 | } 13 | }; -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const OpenSCADFunction = require('./api/OpenSCADFunction'); 2 | const ThreeDModule = require('./api/ThreeDModule'); 3 | const TwoDModule = require('./api/TwoDModule'); 4 | const Types = require('./types/Types'); 5 | 6 | /** 7 | * @typedef {object} UnitTestSCAD This is the top level object exposed when requiring UnitTestSCAD into a NodeJS script. 8 | * @property {Function} Function Exposes the {@link Function} class for use. This should be used when testing an OpenSCAD function. 9 | * @property {ThreeDModule} ThreeDModule Exposes the {@link ThreeDModule} class for use. This should be used when testing an OpenSCAD module which produces a 3D model. 10 | * @property {TwoDModule} TwoDModule Exposes the {@link TwoDModule} class for use. This should be used when testing an OpenSCAD module which produces a 2D model. 11 | * @property {Types} Types Exposes the {@link Types} object for use. This should be used when performing assertions on a {@link Function}. 12 | */ 13 | module.exports = { 14 | Function: OpenSCADFunction, 15 | ThreeDModule, 16 | TwoDModule, 17 | Types 18 | }; -------------------------------------------------------------------------------- /src/types/TypeConverter.js: -------------------------------------------------------------------------------- 1 | const OpenScadType = require('./Types'); 2 | 3 | function isBoolean(text) { 4 | return ['true', 'false'].includes(text); 5 | } 6 | 7 | function isInf(text) { 8 | return text === 'inf'; 9 | } 10 | 11 | function isNan(text) { 12 | return text === 'nan'; 13 | } 14 | 15 | function isNumber(text) { 16 | return !isNaN(parseFloat(text)); 17 | } 18 | 19 | function isRange(text) { 20 | return text.match(/\[.+(:.+){1,2}\]/) !== null; 21 | } 22 | 23 | function isString(text) { 24 | return text.startsWith('"') && text.endsWith('"'); 25 | } 26 | 27 | function isUndef(text) { 28 | return text === 'undef'; 29 | } 30 | 31 | function isVector(text) { 32 | return text.match(/\[.+,.+\]/) !== null; 33 | } 34 | 35 | const tests = {}; 36 | tests[OpenScadType.BOOLEAN] = isBoolean; 37 | tests[OpenScadType.INF] = isInf; 38 | tests[OpenScadType.NAN] = isNan; 39 | tests[OpenScadType.NUMBER] = isNumber; 40 | tests[OpenScadType.RANGE] = isRange; 41 | tests[OpenScadType.STRING] = isString; 42 | tests[OpenScadType.UNDEF] = isUndef; 43 | tests[OpenScadType.VECTOR] = isVector; 44 | 45 | module.exports = { 46 | getType(text) { 47 | return Object 48 | .keys(tests) 49 | .filter(property => tests[property](text)) 50 | .pop(); 51 | } 52 | }; -------------------------------------------------------------------------------- /src/types/Types.js: -------------------------------------------------------------------------------- 1 | /** @typedef {string} OpenSCADBoolean Represents an OpenSCAD boolean. Equal to 'boolean'. */ 2 | /** @typedef {string} OpenSCADInfinity Represents Infinity in OpenSCAD. Equal to 'inf'. */ 3 | /** @typedef {string} OpenSCADNaN Represents NaN (Not a Number) in OpenSCAD. Equal to 'nan'. */ 4 | /** @typedef {string} OpenSCADNumber Represents an OpenSCAD number. Equal to 'number'. */ 5 | /** @typedef {string} OpenSCADRange Represents an OpenSCAD range. Equal to 'range'. */ 6 | /** @typedef {string} OpenSCADString Represents an OpenSCAD string. Equal to 'string'. */ 7 | /** @typedef {string} OpenSCADUndefined Represents undef (undefined) in OpenSCAD. Equal to 'undefined'. */ 8 | /** @typedef {string} OpenSCADVector Represents an OpenSCAD vector. Equal to 'vector'. */ 9 | 10 | /** 11 | * @typedef {object} Types A collection of the available OpenSCAD types. 12 | * @property {OpenSCADBoolean} BOOLEAN See {@link OpenSCADBoolean}. 13 | * @property {OpenSCADInfinity} INF See {@link OpenSCADInfinity}. 14 | * @property {OpenSCADNaN} NAN See {@link OpenSCADNaN}. 15 | * @property {OpenSCADNumber} NUMBER See {@link OpenSCADNumber}. 16 | * @property {OpenSCADRange} RANGE See {@link OpenSCADRange}. 17 | * @property {OpenSCADString} STRING See {@link OpenSCADString}. 18 | * @property {OpenSCADUndefined} UNDEF See {@link OpenSCADUndefined}. 19 | * @property {OpenSCADVector} VECTOR See {@link OpenSCADVector}. 20 | */ 21 | module.exports = { 22 | BOOLEAN: 'boolean', 23 | INF: 'inf', 24 | NAN: 'nan', 25 | NUMBER: 'number', 26 | RANGE: 'range', 27 | STRING: 'string', 28 | UNDEF: 'undef', 29 | VECTOR: 'vector', 30 | }; --------------------------------------------------------------------------------