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
56 changes: 56 additions & 0 deletions crates/psrs-driver/src/tests/foldable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//! The library's `Monoid` and `Foldable` classes.
//!
//! `foldMap` and `fold` are constrained by `Monoid`, so the two classes land
//! together. These tests run the instances, not a second traversal: `Array`
//! walks the compiler's index primitives, and `Maybe` and `Either` fold by
//! cases.

use super::*;

#[test]
fn monoid_identities_and_folds_run_under_wasmtime() {
let source = r#"
module Main where

import Prelude
import Effect.Console (log)
import Data.Monoid (mempty)
import Data.Foldable (class Foldable, foldl, foldr, foldMap)
import Data.Maybe (Maybe(..))
import Data.Either (Either(..))

data One a = One a

instance foldableOne :: Foldable One where
foldr f z (One x) = f x z
foldl f z (One x) = f z x
foldMap f (One x) = f x

checks :: Effect Unit
checks = do
log (foldr (\x acc -> x <> acc) ":" ["a", "b"])
log (foldl (\acc x -> acc <> x) ":" ["a", "b"])
log (foldMap (\x -> x <> "!") ["a", "b"])
log (if arrayLength (mempty :: Array Int) == 0 then "empty-array" else "empty-array-wrong")
log (if (mempty :: Unit) == unit then "empty-unit" else "empty-unit-wrong")
log mempty
log (foldr (\x acc -> x <> acc) "z" (Right "r" :: Either Int String))
log (foldr (\x acc -> x <> acc) "z" (Left 1 :: Either Int String))
log (foldl (\acc x -> acc <> x) "z" (Just "m"))
log (foldMap (\x -> x) (Nothing :: Maybe String))
log (foldMap (\x -> x) (One "one"))
pure unit

main = let ignored = runEffect checks in 0
"#;
let Some(output) = run_with_wasmtime(source) else {
eprintln!("skipping: wasmtime is not installed");
return;
};
assert_eq!(output.status.code(), Some(0), "{output:?}");
assert_eq!(
output.stdout,
"ab:\n:ab\na!b!\nempty-array\nempty-unit\n\nrz\nz\nzm\n\none\n".as_bytes(),
"monoid identities and folds must match the class instances: {output:?}"
);
}
2 changes: 2 additions & 0 deletions crates/psrs-driver/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ mod data_function;
mod deriving;
mod effect_arity;
mod effects;
mod foldable;
mod guard_coverage;
mod operators;
mod partial_application;
mod scalars;
mod semigroup;
mod show;

fn lower_source_to_mir(source: &str) -> psrs_backend::mir::Module {
let core = lower_source_to_core("Main.purs", source).expect("source should lower to Core");
Expand Down
6 changes: 6 additions & 0 deletions crates/psrs-driver/src/tests/module_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,17 @@ fn loads_the_standard_library_from_disk_in_trusted_order() {
"Prelude",
"Data.Function",
"Data.Semigroup",
"Data.Monoid",
"Data.Eq",
"Data.Ord",
"Data.Semiring",
"Data.Show",
"Effect",
"Effect.Console",
"Test.Assert",
"Data.Maybe",
"Data.Either",
"Data.Foldable",
"WASI.Resource",
"WASI.IO",
"WASI.Clock",
Expand All @@ -128,14 +131,17 @@ fn loads_the_standard_library_from_disk_in_trusted_order() {
path.ends_with("lib/Prelude.purs")
|| path.ends_with("lib/Data/Function.purs")
|| path.ends_with("lib/Data/Semigroup.purs")
|| path.ends_with("lib/Data/Monoid.purs")
|| path.ends_with("lib/Data/Eq.purs")
|| path.ends_with("lib/Data/Ord.purs")
|| path.ends_with("lib/Data/Semiring.purs")
|| path.ends_with("lib/Data/Show.purs")
|| path.ends_with("lib/Effect.purs")
|| path.ends_with("lib/Effect/Console.purs")
|| path.ends_with("lib/Test/Assert.purs")
|| path.ends_with("lib/Data/Maybe.purs")
|| path.ends_with("lib/Data/Either.purs")
|| path.ends_with("lib/Data/Foldable.purs")
|| path.ends_with("lib/WASI/Resource.purs")
|| path.ends_with("lib/WASI/IO.purs")
|| path.ends_with("lib/WASI/Clock.purs")
Expand Down
112 changes: 112 additions & 0 deletions crates/psrs-driver/src/tests/show.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
//! The library's `Show` class.
//!
//! These tests execute under Wasmtime. The strings are the official `Show`
//! spellings: `true`/`false`, decimal `Int`, `unit`, quoted `Char` and
//! `String` (with the official escapes), arrays without spaces, and `Number`
//! with a trailing `.0` on an integer token.

use super::*;

#[test]
fn show_renders_the_instances_the_corpus_prints() {
let source = r#"
module Main where

import Prelude
import Effect.Console (log)

checks :: Effect Unit
checks = do
log (show true)
log (show false)
log (show 0)
log (show 42)
log (show (0 - 7))
log (show ((0 - 2147483647) - 1))
log (show unit)
log (show "hi")
log (show "a\"b")
log (show "line\n")
log (show 'a')
log (show '\n')
log (show '\'')
log (show [1, 2, 3])
log (show [1.0, 2.0])
log (show 0.0)
log (show 1.0)
log (show (numberNeg 2.0))
log (show 1.5)
log (show 0.5)
log (show 0.25)
log (show 10000000000.0)
log (show 1.0e21)
log (show 1.0e-5)
log (show "é")
log (show "cafés")
pure unit

main = let ignored = runEffect checks in 0
"#;
let Some(output) = run_with_wasmtime(source) else {
eprintln!("skipping: wasmtime is not installed");
return;
};
assert_eq!(output.status.code(), Some(0), "{output:?}");
let stdout = String::from_utf8_lossy(&output.stdout);
let expected = concat!(
"true\n",
"false\n",
"0\n",
"42\n",
"-7\n",
"-2147483648\n",
"unit\n",
"\"hi\"\n",
"\"a\\\"b\"\n",
"\"line\\n\"\n",
"'a'\n",
"'\\n'\n",
"'\\''\n",
"[1,2,3]\n",
"[1.0,2.0]\n",
"0.0\n",
"1.0\n",
"-2.0\n",
"1.5\n",
"0.5\n",
"0.25\n",
"10000000000.0\n",
"1e+21\n",
"0.00001\n",
"\"é\"\n",
"\"cafés\"\n",
);
assert_eq!(
stdout.as_ref(),
expected,
"stdout:\n{stdout}\nstderr:\n{}",
String::from_utf8_lossy(&output.stderr)
);
}

#[test]
fn a_type_without_show_is_rejected() {
let source = r#"
module Main where

import Prelude

data Box = Box

main :: String
main = show Box
"#;
let errors = check_program_types_lenient_with_prelude(&[("Main.purs", source)])
.expect_err("Box is not a Show");
assert!(
errors
.iter()
.any(|error| error.diagnostic.code == Some("NoInstanceFound")),
"expected NoInstanceFound, got {errors:?}"
);
}
Loading
Loading