Merge pull request #6770 from roc-lang/move-basic-cli-tests

Move basic cli tests from examples
This commit is contained in:
Anton-4 2024-05-22 16:13:40 +02:00 committed by GitHub
commit f10f18980d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
43 changed files with 20 additions and 2254 deletions

View file

@ -0,0 +1,66 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
import pf.Stdout
import pf.Arg
import pf.Task exposing [Task]
main =
args = Arg.list!
parser =
divCmd =
Arg.succeed (\dividend -> \divisor -> Div (Num.toF64 dividend) (Num.toF64 divisor))
|> Arg.withParser
(
Arg.i64Option {
long: "dividend",
short: "n",
help: "the number to divide; corresponds to a numerator",
}
)
|> Arg.withParser
(
Arg.i64Option {
long: "divisor",
short: "d",
help: "the number to divide by; corresponds to a denominator",
}
)
|> Arg.subCommand "div"
logCmd =
Arg.succeed (\base -> \num -> Log (Num.toF64 base) (Num.toF64 num))
|> Arg.withParser
(
Arg.i64Option {
long: "base",
short: "b",
help: "base of the logarithm",
}
)
|> Arg.withParser
(
Arg.i64Option {
long: "num",
help: "the number to take the logarithm of",
}
)
|> Arg.subCommand "log"
Arg.choice [divCmd, logCmd]
|> Arg.program { name: "args-example", help: "A calculator example of the CLI platform argument parser" }
when Arg.parseFormatted parser args is
Ok cmd ->
runCmd cmd
|> Num.toStr
|> Stdout.line
Err helpMenuErr ->
Task.err (Exit 1 "unable to parse args: $(Inspect.toStr helpMenuErr)")
runCmd = \cmd ->
when cmd is
Div n d -> n / d
Log b n ->
# log_b(n) = log_x(n) / log_x(b) for all x
runCmd (Div (Num.log n) (Num.log b))

View file

@ -0,0 +1,19 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
import pf.Stdin
import pf.Stdout
import pf.Task exposing [await, loop]
main =
_ <- await (Stdout.line "\nLet's count down from 3 together - all you have to do is press <ENTER>.")
_ <- await Stdin.line
loop 3 tick
tick = \n ->
if n == 0 then
_ <- await (Stdout.line "🎉 SURPRISE! Happy Birthday! 🎂")
Task.ok (Done {})
else
_ <- await (n |> Num.toStr |> \s -> "$(s)..." |> Stdout.line)
_ <- await Stdin.line
Task.ok (Step (n - 1))

View file

@ -0,0 +1,36 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
import pf.Stdin
import pf.Stdout
import pf.Task exposing [Task]
main =
_ <- Task.await (Stdout.line "🗣 Shout into this cave and hear the echo! 👂👂👂")
Task.loop {} tick
tick : {} -> Task [Step {}, Done {}] _
tick = \{} ->
when Stdin.line |> Task.result! is
Ok str -> Stdout.line (echo str) |> Task.map Step
Err (StdinErr EndOfFile) -> Stdout.line (echo "Received end of input (EOF).") |> Task.map Done
Err (StdinErr err) -> Stdout.line (echo "Unable to read input $(Inspect.toStr err)") |> Task.map Done
echo : Str -> Str
echo = \shout ->
silence = \length ->
spaceInUtf8 = 32
List.repeat spaceInUtf8 length
shout
|> Str.toUtf8
|> List.mapWithIndex
(\_, i ->
length = (List.len (Str.toUtf8 shout) - i)
phrase = (List.split (Str.toUtf8 shout) length).before
List.concat (silence (if i == 0 then 2 * length else length)) phrase)
|> List.join
|> Str.fromUtf8
|> Result.withDefault ""

View file

@ -0,0 +1,31 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
import pf.Stdout
import pf.Stderr
import pf.Env
import pf.Task exposing [Task]
main =
task =
Env.decode "EDITOR"
|> Task.await (\editor -> Stdout.line "Your favorite editor is $(editor)!")
|> Task.await (\{} -> Env.decode "SHLVL")
|> Task.await
(\lvl ->
when lvl is
1u8 -> Stdout.line "You're running this in a root shell!"
n ->
lvlStr = Num.toStr n
Stdout.line "Your current shell level is $(lvlStr)!")
|> Task.await \{} -> Env.decode "LETTERS"
Task.attempt task \result ->
when result is
Ok letters ->
joinedLetters = Str.joinWith letters " "
Stdout.line "Your favorite letters are: $(joinedLetters)"
Err _ ->
Stderr.line "I couldn't find your favorite letters in the environment variables!"

View file

@ -0,0 +1,36 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
import pf.Stdout
import pf.Task exposing [Task]
import pf.File
import pf.Path
import pf.Env
import pf.Dir
main : Task {} [Exit I32 Str]_
main =
path = Path.fromStr "out.txt"
task =
cwd = Env.cwd!
Stdout.line! "cwd: $(Path.display cwd)"
dirEntries = Dir.list! cwd
contentsStr = Str.joinWith (List.map dirEntries Path.display) "\n "
Stdout.line! "Directory contents:\n $(contentsStr)\n"
Stdout.line! "Writing a string to out.txt"
File.writeUtf8! path "a string!"
contents = File.readUtf8! path
Stdout.line! "I read the file back. Its contents: \"$(contents)\""
when Task.result! task is
Ok {} -> Stdout.line! "Successfully wrote a string to out.txt"
Err err ->
msg =
when err is
FileWriteErr _ PermissionDenied -> "PermissionDenied"
FileWriteErr _ Unsupported -> "Unsupported"
FileWriteErr _ (Unrecognized _ other) -> other
FileReadErr _ _ -> "Error reading file"
_ -> "Uh oh, there was an error!"
Task.err (Exit 1 msg)

View file

@ -0,0 +1,13 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
import pf.Stdin
import pf.Stdout
import pf.Task exposing [await, Task]
main =
Stdout.line! "What's your first name?"
firstName = Stdin.line!
Stdout.line! "What's your last name?"
lastName = Stdin.line!
Stdout.line "Hi, $(firstName) $(lastName)! 👋"

View file

@ -0,0 +1,7 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
import pf.Stdout
import pf.Task
main =
Stdout.line! "Hello, World!"

View file

@ -0,0 +1,24 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
import pf.Http
import pf.Task exposing [Task]
import pf.Stdout
main =
request = {
method: Get,
headers: [],
url: "http://www.example.com",
mimeType: "",
body: [],
timeout: TimeoutMilliseconds 5000,
}
resp = Http.send! request
output =
when resp |> Http.handleStringResponse is
Err err -> crash (Http.errorToString err)
Ok body -> body
Stdout.line output

View file

@ -0,0 +1,11 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
import pf.Stdout
import "ingested-file.roc" as license
main =
license
|> List.map Num.toU64
|> List.sum
|> Num.toStr
|> Stdout.line!

View file

@ -0,0 +1,12 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
import pf.Stdout
import "ingested-file.roc" as license : _ # A type hole can also be used here.
main =
# Due to how license is used, it will be a List U8.
license
|> List.map Num.toU64
|> List.sum
|> Num.toStr
|> Stdout.line!

View file

@ -0,0 +1,7 @@
app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br" }
import pf.Stdout
import "ingested-file.roc" as ownCode : Str
main =
Stdout.line! "\nThis roc file can print its own source code. The source is:\n\n$(ownCode)"

View file

@ -0,0 +1,52 @@
app [main] {
cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br",
parser: "https://github.com/lukewilliamboswell/roc-parser/releases/download/0.5.2/9VrPjwfQQ1QeSL3CfmWr2Pr9DESdDIXy97pwpuq84Ck.tar.br",
}
import cli.Stdout
import cli.Stderr
import parser.Core exposing [Parser, buildPrimitiveParser, many]
import parser.String exposing [parseStr]
main =
lettersInput = "AAAiBByAABBwBtCCCiAyArBBx"
ifLetterA = \l -> l == A
when parseStr (many letterParser) lettersInput is
Ok letters ->
letters
|> List.keepIf ifLetterA
|> List.map \_ -> 1
|> List.sum
|> Num.toStr
|> \countLetterA -> Stdout.line "I counted $(countLetterA) letter A's!"
Err _ -> Stderr.line "Ooops, something went wrong parsing letters"
Letter : [A, B, C, Other]
letterParser : Parser (List U8) Letter
letterParser =
input <- buildPrimitiveParser
valResult =
when input is
[] -> Err (ParsingFailure "Nothing to parse")
['A', ..] -> Ok A
['B', ..] -> Ok B
['C', ..] -> Ok C
_ -> Ok Other
valResult
|> Result.map \val -> { val, input: List.dropFirst input 1 }
expect
input = "B"
parser = letterParser
result = parseStr parser input
result == Ok B
expect
input = "BCXA"
parser = many letterParser
result = parseStr parser input
result == Ok [B, C, Other, A]

View file

@ -0,0 +1,64 @@
app [main] {
pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br",
parser: "https://github.com/lukewilliamboswell/roc-parser/releases/download/0.5.2/9VrPjwfQQ1QeSL3CfmWr2Pr9DESdDIXy97pwpuq84Ck.tar.br",
}
import pf.Stdout
import pf.Stderr
import pf.Task exposing [Task]
import parser.Core exposing [Parser, map, keep]
import parser.String exposing [strFromUtf8]
import parser.CSV exposing [CSV]
input : Str
input = "Airplane!,1980,\"Robert Hays,Julie Hagerty\"\r\nCaddyshack,1980,\"Chevy Chase,Rodney Dangerfield,Ted Knight,Michael O'Keefe,Bill Murray\""
main =
when CSV.parseStr movieInfoParser input is
Ok movies ->
moviesString =
movies
|> List.map movieInfoExplanation
|> Str.joinWith ("\n")
nMovies = List.len movies |> Num.toStr
Stdout.line "$(nMovies) movies were found:\n\n$(moviesString)\n\nParse success!\n"
Err problem ->
when problem is
ParsingFailure failure ->
Stderr.line "Parsing failure: $(failure)\n"
ParsingIncomplete leftover ->
leftoverStr = leftover |> List.map strFromUtf8 |> List.map (\val -> "\"$(val)\"") |> Str.joinWith ", "
Stderr.line "Parsing incomplete. Following leftover fields while parsing a record: $(leftoverStr)\n"
SyntaxError error ->
Stderr.line "Parsing failure. Syntax error in the CSV: $(error)"
MovieInfo := { title : Str, releaseYear : U64, actors : List Str }
movieInfoParser =
CSV.record (\title -> \releaseYear -> \actors -> @MovieInfo { title, releaseYear, actors })
|> keep (CSV.field CSV.string)
|> keep (CSV.field CSV.u64)
|> keep (CSV.field actorsParser)
actorsParser =
CSV.string
|> map \val -> Str.split val ","
movieInfoExplanation = \@MovieInfo { title, releaseYear, actors } ->
enumeratedActors = enumerate actors
releaseYearStr = Num.toStr releaseYear
"The movie '$(title)' was released in $(releaseYearStr) and stars $(enumeratedActors)"
enumerate : List Str -> Str
enumerate = \elements ->
{ before: inits, others: last } = List.split elements (List.len elements - 1)
last
|> List.prepend (inits |> Str.joinWith ", ")
|> Str.joinWith " and "

View file

@ -478,7 +478,7 @@ mod cli_run {
#[cfg_attr(windows, ignore)]
fn hello_world() {
test_roc_app_slim(
"examples",
"crates/cli/tests/cli",
"helloWorld.roc",
"Hello, World!\n",
UseValgrind::Yes,
@ -716,29 +716,6 @@ mod cli_run {
test_roc_app_slim("examples/gui", "hello-guiBROKEN.roc", "", UseValgrind::No)
}
#[cfg_attr(windows, ignore)] // flaky error; issue #5024
#[serial(breakout)]
#[test]
fn breakout() {
test_roc_app_slim(
"examples/gui/breakout",
"breakoutBROKEN.roc",
"",
UseValgrind::No,
)
}
#[test]
#[serial(breakout)]
fn breakout_hello_gui() {
test_roc_app_slim(
"examples/gui/breakout",
"hello-guiBROKEN.roc",
"",
UseValgrind::No,
)
}
#[test]
#[cfg_attr(windows, ignore)]
fn quicksort() {
@ -778,7 +755,7 @@ mod cli_run {
#[cfg_attr(windows, ignore = "missing __udivdi3 and some other symbols")]
#[serial(cli_platform)]
fn cli_args_check() {
let path = file_path_from_root("examples/cli", "argsBROKEN.roc");
let path = file_path_from_root("crates/cli/tests/cli", "argsBROKEN.roc");
let out = run_roc([CMD_CHECK, path.to_str().unwrap()], &[], &[]);
assert!(out.status.success());
}
@ -805,7 +782,7 @@ mod cli_run {
#[cfg_attr(windows, ignore)]
#[serial(cli_platform)]
fn cli_countdown_check() {
let path = file_path_from_root("examples/cli", "countdown.roc");
let path = file_path_from_root("crates/cli/tests/cli", "countdown.roc");
let out = run_roc([CMD_CHECK, path.to_str().unwrap()], &[], &[]);
assert!(out.status.success());
}
@ -814,7 +791,7 @@ mod cli_run {
#[cfg_attr(windows, ignore)]
#[serial(cli_platform)]
fn cli_echo_check() {
let path = file_path_from_root("examples/cli", "echo.roc");
let path = file_path_from_root("crates/cli/tests/cli", "echo.roc");
let out = run_roc([CMD_CHECK, path.to_str().unwrap()], &[], &[]);
assert!(out.status.success());
}
@ -823,7 +800,7 @@ mod cli_run {
#[cfg_attr(windows, ignore)]
#[serial(cli_platform)]
fn cli_file_check() {
let path = file_path_from_root("examples/cli", "fileBROKEN.roc");
let path = file_path_from_root("crates/cli/tests/cli", "fileBROKEN.roc");
let out = run_roc([CMD_CHECK, path.to_str().unwrap()], &[], &[]);
assert!(out.status.success());
}
@ -832,7 +809,7 @@ mod cli_run {
#[cfg_attr(windows, ignore)]
#[serial(cli_platform)]
fn cli_form_check() {
let path = file_path_from_root("examples/cli", "form.roc");
let path = file_path_from_root("crates/cli/tests/cli", "form.roc");
let out = run_roc([CMD_CHECK, path.to_str().unwrap()], &[], &[]);
assert!(out.status.success());
}
@ -841,7 +818,7 @@ mod cli_run {
#[cfg_attr(windows, ignore)]
#[serial(cli_platform)]
fn cli_http_get_check() {
let path = file_path_from_root("examples/cli", "http-get.roc");
let path = file_path_from_root("crates/cli/tests/cli", "http-get.roc");
let out = run_roc([CMD_CHECK, path.to_str().unwrap()], &[], &[]);
assert!(out.status.success());
}
@ -917,7 +894,7 @@ mod cli_run {
#[cfg_attr(windows, ignore)]
fn with_env_vars() {
test_roc_app(
"examples/cli",
"crates/cli/tests/cli",
"env.roc",
&[],
&[],
@ -939,14 +916,14 @@ mod cli_run {
#[cfg_attr(windows, ignore)]
fn ingested_file() {
test_roc_app(
"examples/cli",
"crates/cli/tests/cli",
"ingested-file.roc",
&[],
&[],
&[],
format!(
"\nThis roc file can print its own source code. The source is:\n\n{}\n",
include_str!("../../../examples/cli/ingested-file.roc")
include_str!("cli/ingested-file.roc")
)
.as_str(),
UseValgrind::No,
@ -959,12 +936,12 @@ mod cli_run {
#[cfg_attr(windows, ignore)]
fn ingested_file_bytes() {
test_roc_app(
"examples/cli",
"crates/cli/tests/cli",
"ingested-file-bytes.roc",
&[],
&[],
&[],
"162088\n",
"27101\n",
UseValgrind::No,
TestCliCommands::Run,
)
@ -974,12 +951,12 @@ mod cli_run {
#[cfg_attr(windows, ignore)]
fn ingested_file_bytes_no_ann() {
test_roc_app(
"examples/cli",
"crates/cli/tests/cli",
"ingested-file-bytes-no-ann.roc",
&[],
&[],
&[],
"162088\n",
"27101\n",
UseValgrind::No,
TestCliCommands::Run,
)
@ -990,8 +967,8 @@ mod cli_run {
#[cfg_attr(windows, ignore)]
fn parse_movies_csv() {
test_roc_app_slim(
"examples/parser",
"parse-movies-csv.roc",
"crates/cli/tests/cli",
"parser-movies-csv.roc",
"2 movies were found:\n\nThe movie 'Airplane!' was released in 1980 and stars Robert Hays and Julie Hagerty\nThe movie 'Caddyshack' was released in 1980 and stars Chevy Chase, Rodney Dangerfield, Ted Knight, Michael O'Keefe and Bill Murray\n\nParse success!\n\n",
UseValgrind::No,
)
@ -1002,8 +979,8 @@ mod cli_run {
#[cfg_attr(windows, ignore)]
fn parse_letter_counts() {
test_roc_app_slim(
"examples/parser",
"letter-counts.roc",
"crates/cli/tests/cli",
"parser-letter-counts.roc",
"I counted 7 letter A's!\n",
UseValgrind::No,
)