diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c20368c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +FROM rustlang/rust:nightly-alpine3.10 + +RUN apk --no-cache add bash git npm nodejs + +# Create unprivileged user +RUN addgroup -S duster && adduser -S duster -G duster + +# Install LinkedIn DustJS. Installing it globally before copying in +# the repo to avoid spamming the npm servers with every codebase +# change. +RUN npm install -g dustjs-linkedin + + +# Copy repo into duster user's directory +RUN mkdir /home/duster/duster +WORKDIR /home/duster/duster +COPY . . +RUN chown -R duster:duster /home/duster/duster + +USER duster +RUN git clean -dfxq +RUN cargo build diff --git a/js/README.md b/js/README.md new file mode 100644 index 0000000..993cb49 --- /dev/null +++ b/js/README.md @@ -0,0 +1,59 @@ +Compliance Tests +================ + +These tests run my implementation of LinkedIn's Dust and the official implementation of [LinkedIn's DustJS](https://www.dustjs.com) as compares the output to ensure they match. + +Running in Docker +================= + +Go to the root directory of this repository where there is a `Dockerfile` and run: + +``` sh +docker build -t duster . && docker run --rm -i -t duster +``` + +This command will run through the test cases in `js/test_cases`, comparing the output of the official LinkedIn DustJS implementation against the output of the `duster` implementation. If there are any differences, it will flag the test as a failure. + +The tests have a structure of: + +``` text +test_cases +└── hello_world + ├── input1.json + ├── input2.json + ├── main.dust + └── partial.dust +``` + +The folder name `hello_world` is the name of the test group. For each test group there must be a file named `main.dust`. This file will be the top-level template that gets rendered. All other `*.dust` files will get registered into the dust rendering context as partials, with the same name as their file excluding the file extension. For example, `main.dust` could invoke `partial.dust` with `{>partial/}`. Each `*.json` file is a separate context that will be passed into the dust renderer, making each `*.json` file form a test inside the test group. + +Running Manually +================ + +Individually +------------ + +If you want to invoke the LinkedIn DustJS manually, the `dustjs_shim` expects the json context to be passed in over stdin, and a list of templates to be passed in as arguments, with the first argument serving as the main template. An example invocation from this folder would therefore be: + +``` sh +npm install dustjs-linkedin +cat test_cases/hello_world/input1.json | node dustjs_shim.js test_cases/hello_world/main.dust +``` + +Unlike the docker variant, there is no requirement for the template to be named `main.dust` since it will render the first argument as the main template. Running the same test case through the `duster` implementation would be: + +``` sh +npm install dustjs-linkedin +cat test_cases/hello_world/input1.json | ../target/debug/duster-cli test_cases/hello_world/main.dust +``` + +Batch +----- + +If you instead would like to run the entire compliance test suite manually outside of docker, you can run: + +``` sh +npm install dustjs-linkedin +(cd .. && cargo build) +./run_compliance_suite.bash +``` diff --git a/src/js/dustjs_shim.js b/js/dustjs_shim.js similarity index 100% rename from src/js/dustjs_shim.js rename to js/dustjs_shim.js diff --git a/js/run_compliance_suite.bash b/js/run_compliance_suite.bash new file mode 100755 index 0000000..bcce9ae --- /dev/null +++ b/js/run_compliance_suite.bash @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# +# Runs the full suite of tests against LinkedIn DustJS and duster to compare the result +set -uo pipefail +IFS=$'\n\t' +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +failed_count=0 + +find "$DIR/test_cases" -maxdepth 1 -mindepth 1 -type d | sort | while read test_group; do + failed_count_in_group=0 + test_group_name=$(basename "$test_group") + find "$test_group" -maxdepth 1 -mindepth 1 -type f -name '*.json' | sort | while read test_case; do + failed_count_in_testcase=0 + test_case_file_name=$(basename "$test_case") + test_case_name=${test_case_file_name%.*} + ( + if cmp --quiet <(xargs -a <(find "$test_group" -maxdepth 1 -mindepth 1 -type f -name 'main.dust'; find "$test_group" -maxdepth 1 -mindepth 1 -type f -name '*.dust' ! -name 'main.dust') node dustjs_shim.js < "$test_case") <(xargs -a <(find "$test_group" -maxdepth 1 -mindepth 1 -type f -name 'main.dust'; find "$test_group" -maxdepth 1 -mindepth 1 -type f -name '*.dust' ! -name 'main.dust') ../target/debug/duster-cli < "$test_case"); then + echo "$test_group_name::$test_case_name PASSED" + else + echo "$test_group_name::$test_case_name FAILED" + diff <(xargs -a <(find "$test_group" -maxdepth 1 -mindepth 1 -type f -name 'main.dust'; find "$test_group" -maxdepth 1 -mindepth 1 -type f -name '*.dust' ! -name 'main.dust') node dustjs_shim.js < "$test_case") <(xargs -a <(find "$test_group" -maxdepth 1 -mindepth 1 -type f -name 'main.dust'; find "$test_group" -maxdepth 1 -mindepth 1 -type f -name '*.dust' ! -name 'main.dust') ../target/debug/duster-cli < "$test_case") + exit 1 + fi + ) + if [ $? -ne 0 ]; then + failed_count_in_testcase=$((failed_count_in_testcase + 1)) + fi + echo "testcase failed $failed_count_in_testcase" + done + echo "group failed: $failed_count_in_group" +done + +echo "total failed $failed_count" diff --git a/src/js/test_cases/hello_world/input1.json b/js/test_cases/hello_world/input1.json similarity index 100% rename from src/js/test_cases/hello_world/input1.json rename to js/test_cases/hello_world/input1.json diff --git a/src/js/test_cases/hello_world/input2.json b/js/test_cases/hello_world/input2.json similarity index 100% rename from src/js/test_cases/hello_world/input2.json rename to js/test_cases/hello_world/input2.json diff --git a/src/js/test_cases/hello_world/template.dust b/js/test_cases/hello_world/main.dust similarity index 100% rename from src/js/test_cases/hello_world/template.dust rename to js/test_cases/hello_world/main.dust diff --git a/src/js/README.md b/src/js/README.md deleted file mode 100644 index a9ca9d4..0000000 --- a/src/js/README.md +++ /dev/null @@ -1,11 +0,0 @@ -* Compliance Tests -These tests run my implementation of LinkedIn's Dust and the official implementation of [LinkedIn's DustJS](https://www.dustjs.com) as compares the output to ensure they match. -** Setup -Install LinkedIn's DustJS in order to rust the compliance tests -** Running -The dustjs_shim expects a path to a template file as the first parameter, and it expects a json context over stdin. For example, to invoke it on the command line you could run: -```sh -cat test_cases/hello_world/input1.json | node dustjs_shim.js test_cases/hello_world/main.dust -``` - -Each template will be compiled with the same name as the file without the file extension (so main.dust will be compiled as "main"). THe shim renders the first template passed into it (all the others can be accessed as partials).