Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run example solutions on CI #99

Merged
merged 4 commits into from
Nov 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Test

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

jobs:
ci:
runs-on: ubuntu-20.04

steps:
- name: Checkout repository
uses: actions/checkout@v2

- uses: erlef/[email protected]
with:
otp-version: "23.2"
gleam-version: "0.24.0"

- name: Run tests for all exercises
run: bin/test
66 changes: 66 additions & 0 deletions bin/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env bash

set -euo pipefail

# Synopsis:
# Test the track's exercises.
#
# At a minimum, this file must check if the example/exemplar solution of each
# Practice/Concept Exercise passes the exercise's tests.
#
# To check this, you usually have to (temporarily) replace the exercise's solution files
# with its exemplar/example files.
#
# If your track uses skipped tests, make sure to (temporarily) enable these tests
# before running the tests.
#
# The path to the solution/example/exemplar files can be found in the exercise's
# .meta/config.json file, or possibly inferred from the exercise's directory name.

# Example:
# ./bin/test

exit_code=0

function verify_exercise {
local dir slug implementation_file stub_backup_file module
dir=$(realpath "$1")
slug=$(basename "${dir}")
module=${slug//-/_}
implementation_file="${dir}/.meta/example.gleam"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future, you may want to pull this from the config file, because it's commonplace to use example (or proof.ci) for practice exercises and exemplar for concept exercises.

Copy link
Member Author

@lpil lpil Nov 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that but the other scripts I referenced worked this way, so I figured it would be easier to do this rather than remember how jq works 😁

We can improve this later when we get concepts

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, most tracks hardcoded it too 😄, but some like JavaScript started using the config when provided for more flexibility.

stub_file="${dir}/src/${module}.gleam"
stub_backup_file="${stub_file}.bak"

cp "${stub_file}" "${stub_backup_file}"
cp "${implementation_file}" "${stub_file}"

if ! (cd "$dir" && gleam test)
then
echo "${slug}: proof solution did not pass the tests"
exit_code=1
fi

mv "${stub_backup_file}" "${stub_file}"
}

# Verify the Concept Exercises
for concept_exercise_dir in ./exercises/concept/*/
do
if [ -d "$concept_exercise_dir" ]
then
echo "Checking $(basename "${concept_exercise_dir}") concept exercise..."
verify_exercise "${concept_exercise_dir}"
fi
done

# Verify the Practice Exercises
for practice_exercise_dir in ./exercises/practice/*/
do
if [ -d "$practice_exercise_dir" ]
then
echo "Checking $(basename "${practice_exercise_dir}") practice exercise..."
verify_exercise "${practice_exercise_dir}"
fi
done

exit ${exit_code}
3 changes: 1 addition & 2 deletions exercises/practice/bowling/.meta/example.gleam
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import gleam/list
import gleam/bool
import gleam/result

pub opaque type Frame {
Expand All @@ -26,7 +25,7 @@ fn is_frame_rolls_valid(frame: Frame) -> Bool {
}

fn is_frame_open(frame: Frame) -> Bool {
list.length(frame.rolls) == 2 && frame.rolls(score_rolls) < 10
list.length(frame.rolls) == 2 && score_rolls(frame.rolls) < 10
}

fn is_frame_strike(frame: Frame) -> Bool {
Expand Down
3 changes: 0 additions & 3 deletions exercises/practice/forth/.meta/example.gleam
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import gleam/result
import gleam/io
import gleam/int
import gleam/map
import gleam/order
import gleam/bool
import gleam/list
import gleam/string
import gleam/string_builder
Expand Down
2 changes: 0 additions & 2 deletions exercises/practice/forth/src/forth.gleam
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import gleam/result

pub type Forth {
Forth
}
Expand Down
2 changes: 0 additions & 2 deletions exercises/practice/forth/test/forth_test.gleam
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import forth
import gleam/result
import gleam/list
import gleam/io
import gleeunit
import gleeunit/should

Expand Down
15 changes: 10 additions & 5 deletions exercises/practice/freelancer-rates/.meta/example.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,20 @@ pub fn daily_rate(hourly_rate: Int) -> Float {

pub fn apply_discount(before_discount: Int, discount: Float) -> Float {
let float_discount = int.to_float(before_discount)
float_discount -. {float_discount *. {discount /. 100.0}}
float_discount -. float_discount *. { discount /. 100.0 }
}

pub fn monthly_rate(hourly_rate: Int, discount: Float) -> Int {
let before_discount = float.round(daily_rate(hourly_rate) *. 22.0)
let after_discount = apply_discount(before_discount, discount)
float.truncate(float.ceiling(after_discount))
let after_discount = apply_discount(before_discount, discount)
float.truncate(float.ceiling(after_discount))
}

pub fn days_in_budget(budget: Int, hourly_rate: Int, discount: Float) -> Float {
float.floor( int.to_float(budget) /. apply_discount(float.round(daily_rate(hourly_rate)), discount))
}
float.floor(
int.to_float(budget) /. apply_discount(
float.round(daily_rate(hourly_rate)),
discount,
),
)
}