Skip to content
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
48 changes: 9 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Exercism exercises in Pyret.
If you're solving Exercism exercises offline, you'll need a recent copy of [pyret-npm](https://www.npmjs.com/package/pyret-npm) (0.0.27+).
Currently, pyret-npm works on Linux and MacOS platforms although Windows users can run it via the [WSL](https://learn.microsoft.com/en-us/windows/wsl/).
However, you can also use [Pyret's online IDE](https://code.pyret.org/).
In that case, you'll need to switch from the IDE's default `essentials2021` namespace to the older `essentials2020` supported by pyret-npm.
In that case, you'll need to switch from the IDE's default `essentials2021` namespace to the older `starter2024` supported by pyret-npm.

## Support

Expand All @@ -28,52 +28,22 @@ This command will iterate over all exercises and check to see if their exemplar/

Please see [Exercism's contributing guide](https://exercism.org/docs/building).

At the moment, there's not a generator for Pyret exercises.

Here's the basic template for an `exercise-slug-test`.arr.
Each `check` block corresponds to a single test case, and the string label is reported to the student.
Each `check` block is wrapped inside a no-parameter function which is then stored inside the `run` field of a `test` value of the `TestRun` datatype.
This `test` value also contains an `active` field which indicates whether a test should be run (`true`) or not (`false`).
All `test` values go inside a list that Pyret iterates over at runtime, executing the functions within each `test` value marked as active.

A contributor is responsible for copying this template, adding the appropriate functions and `check` blocks, and populating the list at the bottom.
Here's the basic template for an `<slug>-test.arr`.
Each `check` block corresponds to a single test case, and its label is reported to the student.

```pyret

use context essentials2020

include file("exercise-slug.arr")
use context starter2024

#|
When working offline, all tests except the first one are skipped by default.
Once you get the first test running, unskip the next one until all tests pass locally.
Check the block comment below for further details.
|#
include file("<slug>.arr")

fun foo-returns-1():
check "foo returns 1":
foo() is 1
end
check "foo returns 1":
foo() is 1
end

fun bar-returns-2():
check "bar returns 2":
bar() is 2
end
check "bar returns 2":
bar() is 2
end

#|
Code to run each test. Each line corresponds to a test above and whether it should be run.
To mark a test to be run, replace `false` with `true` on that same line after the comma.
test(test-a, true) will be run. test(test-a, false) will be skipped.
|#

data TestRun: test(run, active) end

[list:
test(foo-returns-1, true),
test(bar-returns-2, false),
].each(lam(t): when t.active: t.run() end end)
```

## Track linting
Expand Down
2 changes: 0 additions & 2 deletions bin/verify-exercises
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,10 @@ for practice_exercise_dir in ./exercises/practice/*/; do

test_file="$practice_exercise_dir/$exercise"-test.arr

sed -i.bak 's/test(\([^)]*\), false/test(\1, true/' $test_file
redirect_file="$practice_exercise_dir/$exercise".out
npx pyret -q $test_file &> $redirect_file
test_output=$(cat $redirect_file)
rm $redirect_file
mv "${test_file}.bak" "$test_file"
test_success=$(echo "${test_output}" | grep -c -E 'Looks shipshape')

if [[ $test_success -le 0 ]]; then
Expand Down
55 changes: 10 additions & 45 deletions docs/TESTS.md
Original file line number Diff line number Diff line change
@@ -1,52 +1,20 @@

# Testing on the Pyret track

## Testing using the web editor
## Getting Started

To run tests, click the "Run Tests" button and all the tests will be run.
After you successfully download an exercise, there will be several files inside, but the most two important are your solution and test files.
In the following example, we've downloaded the Leap exercise.

## Testing locally

Before working locally, see the [installation docs][installation] to set up Pyret.

Each exercise has multiple tests.
When you first download the exercise, only one test will be enabled.
The recommended workflow is to run the test (which should initially fail) and then make changes to your code until that test passes.
Then, enable the next test in the test file (see below for details) and repeat this process(modify the code, run tests, and move on) until all the tests pass.
Some students preemptively enable all the tests before working on the code; this can be overwhelming with how many tests are failing and make it harder to solve the exercise.

### Running tests

Each exercise will have a solution file and a test file.
For instance, the Hello World exercise has both a `hello-world.arr` file and a `hello-world-test.arr` file.
Your code will go into `hello-world.arr`.
To run tests, execute the `pyret` command with the test file as an argument.
For instance, running `pyret hello-world-test.arr` in the `hello-world` directory will run the currently enabled Hello World tests.

### Enabling tests

Every test file has one or more tests, each test wrapped in its own function.
At the bottom, there is a list of `TestRun` values representing the tests to be run.
Each test in the list contains two values: the test function to run and an `active` value which controls whether the test will be executed.
For instance, the `etl-test.arr` file contains four tests, with the first active and the rest inactive.

```pyret
data TestRun: test(run, active) end

[list:
test(single-letter, true),
test(single-score-multiple-letters, false),
test(multiple-scores-multiple-letters, false),
test(multiple-scores-different-numbers-of-letters, false)
].each(lam(t): when t.active: t.run() end end)
```bash
leap/
├── leap.arr # Solution file - your code goes here
├── leap-test.arr # Test cases for the exercise
```

To enable additional tests, change the `active` value from `false` to `true`, and then rerun the test file with the `pyret` command.

~~~~exercism/note
If whle working offline you forget to enable all the tests, Pyret may report that all the (active) tests are passing locally.
When you submit your code, the website may report some tests are not passing (as it may be running additional tests which did not run locally).
~~~~
To run the tests, either use `exercism test` if you've downloaded the official Exercism CLI or run `pyret leap-test.arr`.
Pyret will run the test suite which consists of a series of labeled `check` blocks that test your solution file against specific inputs and expected results.
A critical part of this process is explicitly exporting portions of your code so the test suite can see it.

## provide

Expand Down Expand Up @@ -91,10 +59,7 @@ end

All exercise stubs will have either `provide` or `provide-types` statements set up for your use.

[installation]: https://exercism.org/docs/tracks/pyret/installation
[provide-statement]: https://pyret.org/docs/latest/Provide_Statements.html
[shadowing]: https://pyret.org/docs/latest/Bindings.html#%28part._s~3ashadowing%29
[data-definition]: https://pyret.org/docs/latest/s_declarations.html#%28elem._%28bnf-prod._%28.Pyret._data-decl%29%29%29
[provide-types-statement]: https://pyret.org/docs/latest/Provide_Statements.html


2 changes: 1 addition & 1 deletion exercises/practice/acronym/.meta/example.arr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use context essentials2020 # Don't delete this line when using Pyret on Exercism
use context starter2024

provide: abbreviate end

Expand Down
82 changes: 19 additions & 63 deletions exercises/practice/acronym/acronym-test.arr
Original file line number Diff line number Diff line change
@@ -1,83 +1,39 @@
use context essentials2020
use context starter2024

include file("acronym.arr")

#|
When working offline, all tests except the first one are skipped by default.
Once you get the first test running, unskip the next one until all tests pass locally.
Check the block comment below for further details.
|#

fun basic():
check "basic":
abbreviate("Portable Network Graphics") is "PNG"
end
check "basic":
abbreviate("Portable Network Graphics") is "PNG"
end

fun lowercase-words():
check "lowercase words":
abbreviate("Ruby on Rails") is "ROR"
end
check "lowercase words":
abbreviate("Ruby on Rails") is "ROR"
end

fun punctuation():
check "punctuation":
abbreviate("First In, First Out") is "FIFO"
end
check "punctuation":
abbreviate("First In, First Out") is "FIFO"
end

fun all-caps-word():
check "all caps word":
abbreviate("GNU Image Manipulation Program") is "GIMP"
end
check "all caps word":
abbreviate("GNU Image Manipulation Program") is "GIMP"
end

fun punctuation-without-whitespace():
check "punctuation without whitespace":
abbreviate("Complementary metal-oxide semiconductor") is "CMOS"
end
check "punctuation without whitespace":
abbreviate("Complementary metal-oxide semiconductor") is "CMOS"
end

fun very-long-abbreviation():
check "very long abbreviation":
abbreviate("Rolling On The Floor Laughing So Hard That My Dogs Came Over And Licked Me") is "ROTFLSHTMDCOALM"
end
check "very long abbreviation":
abbreviate("Rolling On The Floor Laughing So Hard That My Dogs Came Over And Licked Me") is "ROTFLSHTMDCOALM"
end

fun consecutive-delimiters():
check "consecutive delimiters":
abbreviate("Something - I made up from thin air") is "SIMUFTA"
end
check "consecutive delimiters":
abbreviate("Something - I made up from thin air") is "SIMUFTA"
end

fun apostrophes():
check "apostrophes":
abbreviate("Halley's Comet") is "HC"
end
check "apostrophes":
abbreviate("Halley's Comet") is "HC"
end

fun underscore-emphasis():
check "underscore emphasis":
abbreviate("The Road _Not_ Taken") is "TRNT"
end
check "underscore emphasis":
abbreviate("The Road _Not_ Taken") is "TRNT"
end

#|
Code to run each test. Each line corresponds to a test above and whether it should be run.
To mark a test to be run, replace `false` with `true` on that same line after the comma.
test(test-a, true) will be run. test(test-a, false) will be skipped.
|#

data TestRun: test(run, active) end

[list:
test(basic, true),
test(lowercase-words, false),
test(punctuation, false),
test(all-caps-word, false),
test(punctuation-without-whitespace, false),
test(very-long-abbreviation, false),
test(consecutive-delimiters, false),
test(apostrophes, false),
test(underscore-emphasis, false)
].each(lam(t): when t.active: t.run() end end)
2 changes: 1 addition & 1 deletion exercises/practice/acronym/acronym.arr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use context essentials2020 # Don't delete this line when using Pyret on Exercism
use context starter2024

provide: abbreviate end

Expand Down
4 changes: 2 additions & 2 deletions exercises/practice/allergies/.meta/example.arr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use context essentials2020 # Don't delete this line when using Pyret on Exercism
use context starter2024

provide-types *

Expand Down Expand Up @@ -37,4 +37,4 @@ data Allergies:

filtered(ALLERGENS, self.score)
end
end
end
Loading