Skip to content

Commit

Permalink
Add smoke tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ErikSchierboom committed Oct 26, 2023
1 parent 6b29788 commit 71a51cf
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 10 deletions.
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ node_modules/
.github
.gitignore
.gitattributes
/tests/
/smoke-tests/
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ src/main.js
.DS_Store
.coverage
/example-output/
/smoke-tests/*/mapping.json
/smoke-tests/*/representation.txt
10 changes: 5 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
FROM node:lts-alpine AS builder

# Working directory as specified by exercism
WORKDIR /opt/elm-representer
WORKDIR /opt/representer

# Create a directory for binaries
RUN mkdir bin
ENV PATH="/opt/elm-representer/bin:${PATH}"
ENV ELM_HOME="/opt/elm-representer/elm_home"
ENV PATH="/opt/representer/bin:${PATH}"
ENV ELM_HOME="/opt/representer/elm_home"

# Install elm and elm-format
COPY package.json package-lock.json elm-tooling.json ./
Expand All @@ -24,6 +24,6 @@ COPY bin/run.sh src/cli.js bin/

# Lightweight runner container
FROM node:lts-alpine
WORKDIR /opt/elm-representer
COPY --from=builder /opt/elm-representer/bin bin
WORKDIR /opt/representer
COPY --from=builder /opt/representer/bin bin
ENTRYPOINT [ "bin/run.sh" ]
28 changes: 28 additions & 0 deletions bin/run-tests-in-docker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env sh

# Synopsis:
# Test the representer Docker image by running it against a predefined set of
# solutions with an expected output.
# The representer Docker image is built automatically.

# Output:
# Outputs the diff of the expected representation and mapping against the
# actual representation and mapping generated by the representer.

# Example:
# ./bin/run-tests-in-docker.sh

# Build the Docker image
docker build --rm -t exercism/elm-representer .

# Run the Docker image using the settings mimicking the production environment
docker run \
--rm \
--network none \
--read-only \
--mount type=bind,source="${PWD}/smoke-tests",destination=/opt/representer/smoke-tests \
--mount type=tmpfs,destination=/tmp \
--volume "${PWD}/bin/run-tests.sh:/opt/representer/bin/run-tests.sh" \
--workdir /opt/representer \
--entrypoint /opt/representer/bin/run-tests.sh \
exercism/elm-representer
33 changes: 33 additions & 0 deletions bin/run-tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env sh

# Synopsis:
# Test the representer by running it against a predefined set of solutions
# with an expected output.

# Output:
# Outputs the diff of the expected representation and mapping against the
# actual representation and mapping generated by the representer.

# Example:
# ./bin/run-tests.sh

exit_code=0

# Iterate over all test directories
for test_dir in smoke-tests/*; do
test_dir_name=$(basename "${test_dir}")
test_dir_path=$(realpath "${test_dir}")

bin/run.sh "${test_dir_name}" "${test_dir_path}" "${test_dir_path}"

for file in representation.txt mapping.json; do
expected_file="expected_${file}"
echo "${test_dir_name}: comparing ${file} to ${expected_file}"

if ! diff "${test_dir_path}/${file}" "${test_dir_path}/${expected_file}"; then
exit_code=1
fi
done
done

exit ${exit_code}
11 changes: 6 additions & 5 deletions bin/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,27 @@ INPUT_DIR="$2"
OUTPUT_DIR="$3"

# Normalize identifiers and remove comments
ELM_FILES=$(ls "$INPUT_DIR"/*.elm)
ELM_FILE_COUNT=$(ls "$INPUT_DIR"/*.elm | wc -l)
ELM_FILES=$(ls "$INPUT_DIR"/src/*.elm)
ELM_FILE_COUNT=$(ls "$INPUT_DIR"/src/*.elm | wc -l)
if [ $ELM_FILE_COUNT == 0 ]; then
echo "No .elm file found"
exit -1
elif [ $ELM_FILE_COUNT -gt 1 ]; then
echo "Multiple .elm files found: $ELM_FILES"
exit -2
fi

ELM_FILEPATH=$ELM_FILES
ELM_FILENAME="$(basename $ELM_FILEPATH)"

echo "Normalizing identifiers in ${OUTPUT_DIR}${ELM_FILENAME}"
echo "Normalizing identifiers in ${ELM_FILES}"
# This also creates the mapping.json file
cat $ELM_FILEPATH | node ./bin/cli.js ${OUTPUT_DIR}mapping.json > ${OUTPUT_DIR}${ELM_FILENAME}
cat "${ELM_FILES}" | node ./bin/cli.js ${OUTPUT_DIR}/mapping.json > "${ELM_FILES}"

echo "Running elm-format"
./bin/elm-format $OUTPUT_DIR --yes

echo "Creating representation.txt"
cat $OUTPUT_DIR/$ELM_FILENAME > $OUTPUT_DIR/representation.txt
cat "${ELM_FILES}" > $OUTPUT_DIR/representation.txt

echo Finished
25 changes: 25 additions & 0 deletions smoke-tests/anagram/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"authors": [
"tgecho"
],
"contributors": [
"nathanielknight",
"parkerl",
"thomchop",
"tuxagon"
],
"files": {
"solution": [
"src/Anagram.elm"
],
"test": [
"tests/Tests.elm"
],
"example": [
".meta/src/Anagram.example.elm"
]
},
"blurb": "Given a word and a list of possible anagrams, select the correct sublist.",
"source": "Inspired by the Extreme Startup game",
"source_url": "https://github.com/rchatley/extreme_startup"
}
10 changes: 10 additions & 0 deletions smoke-tests/anagram/expected_mapping.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"identifier_1": "filterAnagramsOf",
"identifier_2": "word",
"identifier_3": "sortedLowercaseCharactersMatch",
"identifier_4": "notExactlyTheSameWord",
"identifier_5": "candidate",
"identifier_6": "sortedLowercaseCharacters",
"identifier_7": "word1",
"identifier_8": "word2"
}
19 changes: 19 additions & 0 deletions smoke-tests/anagram/expected_representation.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module Anagram exposing (..)
import List as List exposing (filter, sort)
import String exposing (toList, toLower)

identifier_1 : String -> (List String -> List String)
identifier_1 identifier_2 =
List.filter (identifier_3 identifier_2) >> List.filter (identifier_4 identifier_2)

identifier_3 : String -> (String -> Bool)
identifier_3 identifier_2 identifier_5 =
identifier_6 identifier_2 == identifier_6 identifier_5

identifier_4 : String -> (String -> Bool)
identifier_4 identifier_7 identifier_8 =
String.toLower identifier_7 /= String.toLower identifier_8

identifier_6 : String -> List Char
identifier_6 =
String.toLower >> String.toList >> List.sort
40 changes: 40 additions & 0 deletions smoke-tests/anagram/src/Anagram.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
-- This is a demonstration solution that I use when mentoring, any
-- improvements / comments / suggestions welcome.

-- I have changed the name of the exported function from `detect` to `filterAnagramsOf`,
-- as I think it describes the intent better. Most times when you are using this module,
-- this name / function definition will tell you all you need to know, and you won't need
-- to read anything else.

-- If you want to know how the algorithm works (the stipulation that idenitcal words be
-- removed is a debatable point for example) then you only have to read the body of
-- `filterAnaagramsOf`.

-- So to understand what this does and how it does it there are only 4 lines to read,
-- which I think is powerful.

-- There is a solution available that uses more point free style
module Anagram exposing (..)

import List as List exposing (filter, sort)
import String exposing (toList, toLower)

filterAnagramsOf : String -> List String -> List String
filterAnagramsOf word =
List.filter (sortedLowercaseCharactersMatch word)
>> List.filter (notExactlyTheSameWord word)


sortedLowercaseCharactersMatch : String -> String -> Bool
sortedLowercaseCharactersMatch word candidate =
sortedLowercaseCharacters word == sortedLowercaseCharacters candidate

notExactlyTheSameWord : String -> String -> Bool
notExactlyTheSameWord word1 word2 =
String.toLower word1 /= String.toLower word2

sortedLowercaseCharacters : String -> List Char
sortedLowercaseCharacters =
String.toLower
>> String.toList
>> List.sort

0 comments on commit 71a51cf

Please sign in to comment.