mirror of
https://github.com/rust-lang/rustlings.git
synced 2025-12-26 00:11:49 +02:00
Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b0b7093e5 | ||
|
|
8387de64d3 | ||
|
|
77de6e5d6a | ||
|
|
8c867a001a | ||
|
|
d01a71f7de | ||
|
|
04d1d4c00e | ||
|
|
d7e58ee1af | ||
|
|
ffb165ce26 | ||
|
|
65cb09eb2e | ||
|
|
78552ebd7a | ||
|
|
0c7bd12372 | ||
|
|
3d11d7685b | ||
|
|
592ae6b4d2 | ||
|
|
4fa79ee02f | ||
|
|
fbd0ccbd5b | ||
|
|
8c008a0e7d | ||
|
|
11fe19d08a | ||
|
|
1b3469f236 | ||
|
|
022921168d | ||
|
|
c6765eb3eb | ||
|
|
c5a374fbf2 | ||
|
|
f3ee70489f | ||
|
|
6a27ba735c | ||
|
|
91dce31265 | ||
|
|
040ca18a64 | ||
|
|
f43cb124f6 | ||
|
|
11875aed6e | ||
|
|
f07703eb7a | ||
|
|
fd4eda8bda | ||
|
|
bf8d927ab2 | ||
|
|
9fc4a83987 | ||
|
|
63280ed9e4 | ||
|
|
25f9d61410 | ||
|
|
c1f4257a91 | ||
|
|
8f9d7ce3d8 | ||
|
|
3b5dfac44e | ||
|
|
a6a8b61b12 | ||
|
|
6cd42bb821 | ||
|
|
4d7ce6e571 | ||
|
|
3f114cc069 | ||
|
|
58ccd72aff | ||
|
|
abf175111d | ||
|
|
9144c816bf | ||
|
|
999601d828 | ||
|
|
10d4d61d19 | ||
|
|
70e59cca3c | ||
|
|
7d6e2812fb | ||
|
|
05e8f02d0a | ||
|
|
9a14d72f08 | ||
|
|
04d0f78a2c |
11
.travis.yml
Normal file
11
.travis.yml
Normal file
@@ -0,0 +1,11 @@
|
||||
language: rust
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
script: cargo test --verbose
|
||||
matrix:
|
||||
allow_failures:
|
||||
- rust: nightly
|
||||
fast_finish: true
|
||||
cache: cargo
|
||||
13
Cargo.toml
13
Cargo.toml
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "rustlings"
|
||||
version = "1.0.0"
|
||||
authors = ["Lynn <819880950@qq.com>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com"]
|
||||
version = "1.1.1"
|
||||
authors = ["Olivia <819880950@qq.com>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
@@ -10,3 +10,12 @@ indicatif = "0.9.0"
|
||||
console = "0.6.2"
|
||||
syntect = "3.0.2"
|
||||
notify = "4.0.0"
|
||||
toml = "0.4.10"
|
||||
serde = {version = "1.0.10", features = ["derive"]}
|
||||
|
||||
[[bin]]
|
||||
name = "rustlings"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd = "0.11.0"
|
||||
|
||||
55
README.md
55
README.md
@@ -13,27 +13,36 @@ Alternatively, for a first-time Rust learner, there's several other resources:
|
||||
|
||||
## Getting Started
|
||||
|
||||
To use `rustlings` you need to have [Rust](https://www.rust-lang.org/) installed on your computer. To install Rust, go to [rustup.rs](https://rustup.rs/).
|
||||
|
||||
Once Rust is installed, clone the `rustlings` repository and enter the resulting directory:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/rust-lang/rustlings.git
|
||||
cd rustlings
|
||||
```
|
||||
|
||||
_Note: If you're on MacOS, make sure you've installed Xcode and its developer tools by typing `xcode-select --install`._
|
||||
|
||||
_Note: If you have Xcode 10+ installed, you also need to install the package file found at `/Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg`._
|
||||
|
||||
Once in the directory you can install `rustlings` on your machine and run the introduction:
|
||||
You will need to have Rust installed. You can get it by visiting https://rustup.rs. This'll also install Cargo, Rust's package/project manager.
|
||||
|
||||
## MacOS/Linux
|
||||
|
||||
Just run:
|
||||
|
||||
```bash
|
||||
cargo install --path .
|
||||
rustlings
|
||||
curl -L https://git.io/rustlings | bash
|
||||
# Or if you want it to be installed to a different path:
|
||||
curl -L https://git.io/rustlings | bash -s mypath/
|
||||
```
|
||||
|
||||
If you choose to not install the `rustlings` command, just replace `rustlings` with `cargo run` in the rest of this text.
|
||||
This will install Rustlings and give you access to the `rustlings` command. Run it to get started!
|
||||
|
||||
## Windows/Manually
|
||||
|
||||
Basically: Clone the repository, checkout to the latest tag, run `cargo install`.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/rust-lang/rustlings
|
||||
cd rustlings
|
||||
git checkout tags/1.0.0 # or whatever the latest version is (find out at https://github.com/rust-lang/rustlings/releases/latest)
|
||||
cargo install --force --path .
|
||||
```
|
||||
|
||||
Same as above, run `rustlings` to get started.
|
||||
|
||||
## Doing exercises
|
||||
|
||||
@@ -59,12 +68,6 @@ In case you want to go by your own order, or want to only verify a single exerci
|
||||
rustlings run exercises/path/to/exercise.rs
|
||||
```
|
||||
|
||||
Or if it's a `#[test]`:
|
||||
|
||||
```bash
|
||||
rustlings run --test exercises/path/to/exercise_with_test.rs
|
||||
```
|
||||
|
||||
In case you get stuck, there is usually a hint at the bottom of each exercise.
|
||||
|
||||
## Testing yourself
|
||||
@@ -96,18 +99,20 @@ If you are interested in improving or adding new ones, please feel free to contr
|
||||
First step is to add the exercise! Call it `exercises/yourTopic/yourTopicN.rs`, make sure to
|
||||
put in some helpful links, and link to sections of the book in `exercises/yourTopic/README.md`.
|
||||
|
||||
Then, you'll want to make sure it gets verified when you run `rustlings verify`. Open `src/verify.rs` and
|
||||
put your exercise somewhere in there:
|
||||
Next you want to make sure it runs when using `rustlings`. All exercises are stored in `info.toml`, under the `exercises` array. They're ordered by the order they're ran when using `rustlings verify`.
|
||||
|
||||
You want to make sure where in the file you add your exercise. If you're not sure, add it at the bottom and ask in your pull request. To add an exercise, edit the file like this:
|
||||
```diff
|
||||
...
|
||||
compile_only("exercises/functions5.rs")?;
|
||||
+ compile_only("exercises/yourTopic/yourTopicN.rs")?;
|
||||
compile_only("exercises/test1.rs")?;
|
||||
+ [[exercises]]
|
||||
+ path = "exercises/yourTopic/yourTopicN.rs"
|
||||
+ mode = "compile"
|
||||
...
|
||||
```
|
||||
|
||||
That's all!
|
||||
The `mode` attribute decides whether Rustlings will only compile your exercise, or compile and test it. If you have tests to verify in your exercise, choose `test`, otherwise `compile`.
|
||||
|
||||
That's all! Feel free to put up a pull request.
|
||||
|
||||
### Working on the source code
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
For this exercise check out the sections:
|
||||
- [Error Handling](https://doc.rust-lang.org/book/2018-edition/ch09-02-recoverable-errors-with-result.html)
|
||||
- [Generics](https://doc.rust-lang.org/book/2018-edition/ch10-01-syntax.html)
|
||||
- [Error Handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html)
|
||||
- [Generics](https://doc.rust-lang.org/book/ch10-01-syntax.html)
|
||||
|
||||
of the Rust Book.
|
||||
of the Rust Book.
|
||||
|
||||
0
exercises/error_handling/errors1.rs
Executable file → Normal file
0
exercises/error_handling/errors1.rs
Executable file → Normal file
2
exercises/error_handling/errors2.rs
Executable file → Normal file
2
exercises/error_handling/errors2.rs
Executable file → Normal file
@@ -68,5 +68,5 @@ mod tests {
|
||||
// `Err(something)`. This pattern is very common in Rust, though, so there's
|
||||
// a `?` operator that does pretty much what you would make that match statement
|
||||
// do for you! Take a look at this section of the Error Handling chapter:
|
||||
// https://doc.rust-lang.org/stable/book/second-edition/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
|
||||
// https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html#a-shortcut-for-propagating-errors-the--operator
|
||||
// and give it a try!
|
||||
|
||||
0
exercises/error_handling/errors3.rs
Executable file → Normal file
0
exercises/error_handling/errors3.rs
Executable file → Normal file
0
exercises/error_handling/errorsn.rs
Executable file → Normal file
0
exercises/error_handling/errorsn.rs
Executable file → Normal file
0
exercises/error_handling/option1.rs
Executable file → Normal file
0
exercises/error_handling/option1.rs
Executable file → Normal file
0
exercises/error_handling/result1.rs
Executable file → Normal file
0
exercises/error_handling/result1.rs
Executable file → Normal file
0
exercises/functions/functions1.rs
Executable file → Normal file
0
exercises/functions/functions1.rs
Executable file → Normal file
0
exercises/functions/functions2.rs
Executable file → Normal file
0
exercises/functions/functions2.rs
Executable file → Normal file
0
exercises/functions/functions3.rs
Executable file → Normal file
0
exercises/functions/functions3.rs
Executable file → Normal file
0
exercises/functions/functions4.rs
Executable file → Normal file
0
exercises/functions/functions4.rs
Executable file → Normal file
0
exercises/functions/functions5.rs
Executable file → Normal file
0
exercises/functions/functions5.rs
Executable file → Normal file
0
exercises/if/if1.rs
Executable file → Normal file
0
exercises/if/if1.rs
Executable file → Normal file
0
exercises/macros/macros1.rs
Executable file → Normal file
0
exercises/macros/macros1.rs
Executable file → Normal file
0
exercises/macros/macros2.rs
Executable file → Normal file
0
exercises/macros/macros2.rs
Executable file → Normal file
0
exercises/macros/macros3.rs
Executable file → Normal file
0
exercises/macros/macros3.rs
Executable file → Normal file
0
exercises/macros/macros4.rs
Executable file → Normal file
0
exercises/macros/macros4.rs
Executable file → Normal file
0
exercises/modules/modules1.rs
Executable file → Normal file
0
exercises/modules/modules1.rs
Executable file → Normal file
0
exercises/modules/modules2.rs
Executable file → Normal file
0
exercises/modules/modules2.rs
Executable file → Normal file
0
exercises/move_semantics/move_semantics1.rs
Executable file → Normal file
0
exercises/move_semantics/move_semantics1.rs
Executable file → Normal file
0
exercises/move_semantics/move_semantics2.rs
Executable file → Normal file
0
exercises/move_semantics/move_semantics2.rs
Executable file → Normal file
0
exercises/move_semantics/move_semantics3.rs
Executable file → Normal file
0
exercises/move_semantics/move_semantics3.rs
Executable file → Normal file
0
exercises/move_semantics/move_semantics4.rs
Executable file → Normal file
0
exercises/move_semantics/move_semantics4.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types1.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types1.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types2.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types2.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types3.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types3.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types4.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types4.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types5.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types5.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types6.rs
Executable file → Normal file
0
exercises/primitive_types/primitive_types6.rs
Executable file → Normal file
0
exercises/standard_library_types/arc1.rs
Executable file → Normal file
0
exercises/standard_library_types/arc1.rs
Executable file → Normal file
0
exercises/standard_library_types/iterator3.rs
Executable file → Normal file
0
exercises/standard_library_types/iterator3.rs
Executable file → Normal file
0
exercises/standard_library_types/iterators4.rs
Executable file → Normal file
0
exercises/standard_library_types/iterators4.rs
Executable file → Normal file
0
exercises/strings/strings1.rs
Executable file → Normal file
0
exercises/strings/strings1.rs
Executable file → Normal file
0
exercises/strings/strings2.rs
Executable file → Normal file
0
exercises/strings/strings2.rs
Executable file → Normal file
0
exercises/test2.rs
Executable file → Normal file
0
exercises/test2.rs
Executable file → Normal file
0
exercises/test3.rs
Executable file → Normal file
0
exercises/test3.rs
Executable file → Normal file
0
exercises/tests/tests1.rs
Executable file → Normal file
0
exercises/tests/tests1.rs
Executable file → Normal file
0
exercises/tests/tests2.rs
Executable file → Normal file
0
exercises/tests/tests2.rs
Executable file → Normal file
0
exercises/tests/tests3.rs
Executable file → Normal file
0
exercises/tests/tests3.rs
Executable file → Normal file
0
exercises/threads/threads1.rs
Executable file → Normal file
0
exercises/threads/threads1.rs
Executable file → Normal file
0
exercises/variables/variables1.rs
Executable file → Normal file
0
exercises/variables/variables1.rs
Executable file → Normal file
0
exercises/variables/variables2.rs
Executable file → Normal file
0
exercises/variables/variables2.rs
Executable file → Normal file
0
exercises/variables/variables3.rs
Executable file → Normal file
0
exercises/variables/variables3.rs
Executable file → Normal file
0
exercises/variables/variables4.rs
Executable file → Normal file
0
exercises/variables/variables4.rs
Executable file → Normal file
213
info.toml
Normal file
213
info.toml
Normal file
@@ -0,0 +1,213 @@
|
||||
# VARIABLES
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/variables/variables1.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/variables/variables2.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/variables/variables3.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/variables/variables4.rs"
|
||||
mode = "compile"
|
||||
|
||||
# IF
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/if/if1.rs"
|
||||
mode = "test"
|
||||
|
||||
# FUNCTIONS
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/functions/functions1.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/functions/functions2.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/functions/functions3.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/functions/functions4.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/functions/functions5.rs"
|
||||
mode = "compile"
|
||||
|
||||
# TEST 1
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/test1.rs"
|
||||
mode = "test"
|
||||
|
||||
# PRIMITIVE TYPES
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/primitive_types/primitive_types1.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/primitive_types/primitive_types2.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/primitive_types/primitive_types3.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/primitive_types/primitive_types4.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/primitive_types/primitive_types5.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/primitive_types/primitive_types6.rs"
|
||||
mode = "compile"
|
||||
|
||||
# TESTS
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/tests/tests1.rs"
|
||||
mode = "test"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/tests/tests2.rs"
|
||||
mode = "test"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/tests/tests3.rs"
|
||||
mode = "test"
|
||||
|
||||
# TEST 2
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/test2.rs"
|
||||
mode = "test"
|
||||
|
||||
# STRINGS
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/strings/strings1.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/strings/strings2.rs"
|
||||
mode = "compile"
|
||||
|
||||
# TEST 3
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/test3.rs"
|
||||
mode = "compile"
|
||||
|
||||
# MODULES
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/modules/modules1.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/modules/modules2.rs"
|
||||
mode = "compile"
|
||||
|
||||
# MACROS
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/macros/macros1.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/macros/macros2.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/macros/macros3.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/macros/macros4.rs"
|
||||
mode = "compile"
|
||||
|
||||
# TEST 4
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/test4.rs"
|
||||
mode = "compile"
|
||||
|
||||
# MOVE SEMANTICS
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/move_semantics/move_semantics1.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/move_semantics/move_semantics2.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/move_semantics/move_semantics3.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/move_semantics/move_semantics4.rs"
|
||||
mode = "compile"
|
||||
|
||||
# ERROR HANDLING
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/error_handling/errors1.rs"
|
||||
mode = "test"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/error_handling/errors2.rs"
|
||||
mode = "test"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/error_handling/errors3.rs"
|
||||
mode = "test"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/error_handling/errorsn.rs"
|
||||
mode = "test"
|
||||
|
||||
# OPTIONS / RESULTS
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/error_handling/option1.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/error_handling/result1.rs"
|
||||
mode = "test"
|
||||
|
||||
# THREADS
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/threads/threads1.rs"
|
||||
mode = "compile"
|
||||
|
||||
# STANDARD LIBRARY TYPES
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/standard_library_types/arc1.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/standard_library_types/iterator3.rs"
|
||||
mode = "test"
|
||||
|
||||
[[exercises]]
|
||||
path = "exercises/standard_library_types/iterators4.rs"
|
||||
mode = "test"
|
||||
103
install.sh
Executable file
103
install.sh
Executable file
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo "Let's get you set up with Rustlings!"
|
||||
|
||||
echo "Checking requirements..."
|
||||
if [ -x "$(command -v git)" ]
|
||||
then
|
||||
echo "SUCCESS: Git is installed"
|
||||
else
|
||||
echo "WARNING: Git does not seem to be installed."
|
||||
echo "Please download Git using your package manager or over https://git-scm.com/!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -x "$(command -v rustc)" ]
|
||||
then
|
||||
echo "SUCCESS: Rust is installed"
|
||||
else
|
||||
echo "WARNING: Rust does not seem to be installed."
|
||||
echo "Please download Rust using https://rustup.rs!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -x "$(command -v cargo)" ]
|
||||
then
|
||||
echo "SUCCESS: Cargo is installed"
|
||||
else
|
||||
echo "WARNING: Cargo does not seem to be installed."
|
||||
echo "Please download Rust and Cargo using https://rustup.rs!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function that compares two versions strings v1 and v2 given in arguments (e.g 1.31 and 1.33.0).
|
||||
# Returns 1 if v1 > v2, 0 if v1 == v2, 2 if v1 < v2.
|
||||
function vercomp() {
|
||||
if [[ $1 == $2 ]]
|
||||
then
|
||||
return 0
|
||||
fi
|
||||
v1=( ${1//./ } )
|
||||
v2=( ${2//./ } )
|
||||
len1=${#v1[@]}
|
||||
len2=${#v2[@]}
|
||||
max_len=$len1
|
||||
if [[ $max_len -lt $len2 ]]
|
||||
then
|
||||
max_len=$len2
|
||||
fi
|
||||
for i in `seq 0 $max_len`
|
||||
do
|
||||
# Fill empty fields with zeros in v1
|
||||
if [ -z "${v1[$i]}" ]
|
||||
then
|
||||
v1[$i]=0
|
||||
fi
|
||||
# And in v2
|
||||
if [ -z "${v2[$i]}" ]
|
||||
then
|
||||
v2[$i]=0
|
||||
fi
|
||||
if [ ${v1[$i]} -gt ${v2[$i]} ]
|
||||
then
|
||||
return 1
|
||||
fi
|
||||
if [ ${v1[$i]} -lt ${v2[$i]} ]
|
||||
then
|
||||
return 2
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
RustVersion=$(rustc --version | cut -d " " -f 2)
|
||||
MinRustVersion=1.31
|
||||
vercomp $RustVersion $MinRustVersion
|
||||
if [ $? -eq 2 ]
|
||||
then
|
||||
echo "WARNING: Rust version is too old: $RustVersion - needs at least $MinRustVersion"
|
||||
echo "Please update Rust with 'rustup update'"
|
||||
exit 1
|
||||
else
|
||||
echo "SUCCESS: Rust is up to date"
|
||||
fi
|
||||
|
||||
Path=${1:-rustlings/}
|
||||
echo "Cloning Rustlings at $Path..."
|
||||
git clone -q https://github.com/rust-lang/rustlings $Path
|
||||
|
||||
Version=$(curl -s https://api.github.com/repos/rust-lang/rustlings/releases/latest | python -c "import json,sys;obj=json.load(sys.stdin);print(obj['tag_name']);")
|
||||
echo "Checking out version $Version..."
|
||||
cd $Path
|
||||
git checkout -q tags/$Version
|
||||
|
||||
echo "Installing the 'rustlings' executable..."
|
||||
cargo install --force --path .
|
||||
|
||||
if [ -x "$(rustlings)" ]
|
||||
then
|
||||
echo "WARNING: Please check that you have '~/.cargo/bin' in your PATH environment variable!"
|
||||
fi
|
||||
|
||||
echo "All done! Run 'rustlings' to get started."
|
||||
|
||||
79
src/exercise.rs
Normal file
79
src/exercise.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use serde::Deserialize;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::fs::{remove_file};
|
||||
use std::path::{PathBuf};
|
||||
use std::process::{self, Command, Output};
|
||||
|
||||
const RUSTC_COLOR_ARGS: &[&str] = &["--color", "always"];
|
||||
|
||||
fn temp_file() -> String {
|
||||
format!("./temp_{}", process::id())
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum Mode {
|
||||
Compile,
|
||||
Test,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ExerciseList {
|
||||
pub exercises: Vec<Exercise>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Exercise {
|
||||
pub path: PathBuf,
|
||||
pub mode: Mode,
|
||||
}
|
||||
|
||||
impl Exercise {
|
||||
pub fn compile(&self) -> Output {
|
||||
match self.mode {
|
||||
Mode::Compile => Command::new("rustc")
|
||||
.args(&[self.path.to_str().unwrap(), "-o", &temp_file()])
|
||||
.args(RUSTC_COLOR_ARGS)
|
||||
.output(),
|
||||
Mode::Test => Command::new("rustc")
|
||||
.args(&["--test", self.path.to_str().unwrap(), "-o", &temp_file()])
|
||||
.args(RUSTC_COLOR_ARGS)
|
||||
.output(),
|
||||
}
|
||||
.expect("Failed to run 'compile' command.")
|
||||
}
|
||||
|
||||
pub fn run(&self) -> Output {
|
||||
Command::new(&temp_file())
|
||||
.output()
|
||||
.expect("Failed to run 'run' command")
|
||||
}
|
||||
|
||||
pub fn clean(&self) {
|
||||
let _ignored = remove_file(&temp_file());
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Exercise {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.path.to_str().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use std::path::Path;
|
||||
use std::fs::File;
|
||||
|
||||
#[test]
|
||||
fn test_clean() {
|
||||
File::create(&temp_file()).unwrap();
|
||||
let exercise = Exercise {
|
||||
path: PathBuf::from("example.rs"),
|
||||
mode: Mode::Test,
|
||||
};
|
||||
exercise.clean();
|
||||
assert!(!Path::new(&temp_file()).exists());
|
||||
}
|
||||
}
|
||||
72
src/main.rs
72
src/main.rs
@@ -1,9 +1,13 @@
|
||||
use crate::exercise::{Exercise, ExerciseList};
|
||||
use crate::run::run;
|
||||
use crate::verify::verify;
|
||||
use clap::{crate_version, App, Arg, SubCommand};
|
||||
use notify::DebouncedEvent;
|
||||
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use std::io::BufRead;
|
||||
use std::path::Path;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::time::Duration;
|
||||
use syntect::easy::HighlightFile;
|
||||
@@ -11,8 +15,8 @@ use syntect::highlighting::{Style, ThemeSet};
|
||||
use syntect::parsing::SyntaxSet;
|
||||
use syntect::util::as_24_bit_terminal_escaped;
|
||||
|
||||
mod exercise;
|
||||
mod run;
|
||||
mod util;
|
||||
mod verify;
|
||||
|
||||
fn main() {
|
||||
@@ -35,7 +39,7 @@ fn main() {
|
||||
let ts = ThemeSet::load_defaults();
|
||||
|
||||
if None == matches.subcommand_name() {
|
||||
println!("");
|
||||
println!();
|
||||
println!(r#" welcome to... "#);
|
||||
println!(r#" _ _ _ "#);
|
||||
println!(r#" _ __ _ _ ___| |_| (_)_ __ __ _ ___ "#);
|
||||
@@ -43,25 +47,50 @@ fn main() {
|
||||
println!(r#" | | | |_| \__ \ |_| | | | | | (_| \__ \ "#);
|
||||
println!(r#" |_| \__,_|___/\__|_|_|_| |_|\__, |___/ "#);
|
||||
println!(r#" |___/ "#);
|
||||
println!("");
|
||||
println!();
|
||||
}
|
||||
|
||||
if let Some(matches) = matches.subcommand_matches("run") {
|
||||
run(matches.clone());
|
||||
if !Path::new("info.toml").exists() {
|
||||
println!(
|
||||
"{} must be run from the rustlings directory",
|
||||
std::env::current_exe().unwrap().to_str().unwrap()
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
if let Some(_) = matches.subcommand_matches("verify") {
|
||||
match verify() {
|
||||
Ok(_) => {}
|
||||
Err(_) => std::process::exit(1),
|
||||
}
|
||||
let toml_str = &fs::read_to_string("info.toml").unwrap();
|
||||
let exercises = toml::from_str::<ExerciseList>(toml_str).unwrap().exercises;
|
||||
|
||||
if let Some(ref matches) = matches.subcommand_matches("run") {
|
||||
let filename = matches.value_of("file").unwrap_or_else(|| {
|
||||
println!("Please supply a file name!");
|
||||
std::process::exit(1);
|
||||
});
|
||||
|
||||
let matching_exercise = |e: &&Exercise| {
|
||||
Path::new(filename)
|
||||
.canonicalize()
|
||||
.map(|p| p.ends_with(&e.path))
|
||||
.unwrap_or(false)
|
||||
};
|
||||
|
||||
let exercise = exercises.iter().find(matching_exercise).unwrap_or_else(|| {
|
||||
println!("No exercise found for your file name!");
|
||||
std::process::exit(1)
|
||||
});
|
||||
|
||||
run(&exercise).unwrap_or_else(|_| std::process::exit(1));
|
||||
}
|
||||
|
||||
if let Some(_) = matches.subcommand_matches("watch") {
|
||||
watch().unwrap();
|
||||
if matches.subcommand_matches("verify").is_some() {
|
||||
verify(&exercises).unwrap_or_else(|_| std::process::exit(1));
|
||||
}
|
||||
|
||||
if let None = matches.subcommand_name() {
|
||||
if matches.subcommand_matches("watch").is_some() {
|
||||
watch(&exercises).unwrap();
|
||||
}
|
||||
|
||||
if matches.subcommand_name().is_none() {
|
||||
let mut highlighter =
|
||||
HighlightFile::new("default_out.md", &ss, &ts.themes["base16-eighties.dark"]).unwrap();
|
||||
for maybe_line in highlighter.reader.lines() {
|
||||
@@ -74,19 +103,26 @@ fn main() {
|
||||
println!("\x1b[0m");
|
||||
}
|
||||
|
||||
fn watch() -> notify::Result<()> {
|
||||
fn watch(exercises: &[Exercise]) -> notify::Result<()> {
|
||||
let (tx, rx) = channel();
|
||||
|
||||
let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(2))?;
|
||||
watcher.watch("./exercises", RecursiveMode::Recursive)?;
|
||||
watcher.watch(Path::new("./exercises"), RecursiveMode::Recursive)?;
|
||||
|
||||
let _ignored = verify();
|
||||
let _ignored = verify(exercises.iter());
|
||||
|
||||
loop {
|
||||
match rx.recv() {
|
||||
Ok(event) => match event {
|
||||
DebouncedEvent::Chmod(_) | DebouncedEvent::Write(_) => {
|
||||
let _ignored = verify();
|
||||
DebouncedEvent::Create(b) | DebouncedEvent::Chmod(b) | DebouncedEvent::Write(b) => {
|
||||
if b.extension() == Some(OsStr::new("rs")) {
|
||||
println!("----------**********----------\n");
|
||||
let filepath = b.as_path().canonicalize().unwrap();
|
||||
let exercise = exercises
|
||||
.iter()
|
||||
.skip_while(|e| !filepath.ends_with(&e.path));
|
||||
let _ignored = verify(exercise);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
|
||||
83
src/run.rs
83
src/run.rs
@@ -1,55 +1,52 @@
|
||||
use crate::util::clean;
|
||||
use crate::exercise::{Mode, Exercise};
|
||||
use crate::verify::test;
|
||||
use console::{style, Emoji};
|
||||
use indicatif::ProgressBar;
|
||||
use std::process::Command;
|
||||
|
||||
pub fn run(matches: clap::ArgMatches) {
|
||||
if let Some(filename) = matches.value_of("file") {
|
||||
if matches.is_present("test") {
|
||||
match test(filename) {
|
||||
Ok(_) => (),
|
||||
Err(_) => (),
|
||||
}
|
||||
std::process::exit(0);
|
||||
}
|
||||
let bar = ProgressBar::new_spinner();
|
||||
bar.set_message(format!("Compiling {}...", filename).as_str());
|
||||
bar.enable_steady_tick(100);
|
||||
let compilecmd = Command::new("rustc")
|
||||
.args(&[filename, "-o", "temp", "--color", "always"])
|
||||
.output()
|
||||
.expect("fail");
|
||||
bar.set_message(format!("Running {}...", filename).as_str());
|
||||
if compilecmd.status.success() {
|
||||
let runcmd = Command::new("./temp").output().expect("fail");
|
||||
bar.finish_and_clear();
|
||||
pub fn run(exercise: &Exercise) -> Result<(), ()> {
|
||||
match exercise.mode {
|
||||
Mode::Test => test(exercise)?,
|
||||
Mode::Compile => compile_and_run(exercise)?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
if runcmd.status.success() {
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
|
||||
let formatstr = format!("{} Successfully ran {}", Emoji("✅", "✓"), filename);
|
||||
println!("{}", style(formatstr).green());
|
||||
clean();
|
||||
} else {
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stderr));
|
||||
pub fn compile_and_run(exercise: &Exercise) -> Result<(), ()> {
|
||||
let progress_bar = ProgressBar::new_spinner();
|
||||
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
|
||||
let formatstr = format!("{} Ran {} with errors", Emoji("⚠️ ", "!"), filename);
|
||||
println!("{}", style(formatstr).red());
|
||||
clean();
|
||||
}
|
||||
let compilecmd = exercise.compile();
|
||||
progress_bar.set_message(format!("Running {}...", exercise).as_str());
|
||||
if compilecmd.status.success() {
|
||||
let runcmd = exercise.run();
|
||||
progress_bar.finish_and_clear();
|
||||
|
||||
if runcmd.status.success() {
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
|
||||
let formatstr = format!("{} Successfully ran {}", Emoji("✅", "✓"), exercise);
|
||||
println!("{}", style(formatstr).green());
|
||||
exercise.clean();
|
||||
Ok(())
|
||||
} else {
|
||||
bar.finish_and_clear();
|
||||
let formatstr = format!(
|
||||
"{} Compilation of {} failed! Compiler error message:\n",
|
||||
Emoji("⚠️ ", "!"),
|
||||
filename
|
||||
);
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stderr));
|
||||
|
||||
let formatstr = format!("{} Ran {} with errors", Emoji("⚠️ ", "!"), exercise);
|
||||
println!("{}", style(formatstr).red());
|
||||
println!("{}", String::from_utf8_lossy(&compilecmd.stderr));
|
||||
clean();
|
||||
exercise.clean();
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
panic!("Please supply a filename!");
|
||||
progress_bar.finish_and_clear();
|
||||
let formatstr = format!(
|
||||
"{} Compilation of {} failed! Compiler error message:\n",
|
||||
Emoji("⚠️ ", "!"),
|
||||
exercise
|
||||
);
|
||||
println!("{}", style(formatstr).red());
|
||||
println!("{}", String::from_utf8_lossy(&compilecmd.stderr));
|
||||
exercise.clean();
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
use std::fs::remove_file;
|
||||
|
||||
pub fn clean() {
|
||||
let _ignored = remove_file("temp");
|
||||
}
|
||||
119
src/verify.rs
119
src/verify.rs
@@ -1,124 +1,83 @@
|
||||
use crate::util::clean;
|
||||
use crate::exercise::{Exercise, Mode};
|
||||
use console::{style, Emoji};
|
||||
use indicatif::ProgressBar;
|
||||
use std::process::Command;
|
||||
|
||||
pub fn verify() -> Result<(), ()> {
|
||||
compile_only("exercises/variables/variables1.rs")?;
|
||||
compile_only("exercises/variables/variables2.rs")?;
|
||||
compile_only("exercises/variables/variables3.rs")?;
|
||||
compile_only("exercises/variables/variables4.rs")?;
|
||||
test("exercises/if/if1.rs")?;
|
||||
compile_only("exercises/functions/functions1.rs")?;
|
||||
compile_only("exercises/functions/functions2.rs")?;
|
||||
compile_only("exercises/functions/functions3.rs")?;
|
||||
compile_only("exercises/functions/functions4.rs")?;
|
||||
compile_only("exercises/functions/functions5.rs")?;
|
||||
test("exercises/test1.rs")?;
|
||||
compile_only("exercises/primitive_types/primitive_types1.rs")?;
|
||||
compile_only("exercises/primitive_types/primitive_types2.rs")?;
|
||||
compile_only("exercises/primitive_types/primitive_types3.rs")?;
|
||||
compile_only("exercises/primitive_types/primitive_types4.rs")?;
|
||||
compile_only("exercises/primitive_types/primitive_types5.rs")?;
|
||||
compile_only("exercises/primitive_types/primitive_types6.rs")?;
|
||||
test("exercises/tests/tests1.rs")?;
|
||||
test("exercises/tests/tests2.rs")?;
|
||||
test("exercises/tests/tests3.rs")?;
|
||||
test("exercises/test2.rs")?;
|
||||
compile_only("exercises/strings/strings1.rs")?;
|
||||
compile_only("exercises/strings/strings2.rs")?;
|
||||
compile_only("exercises/test3.rs")?;
|
||||
compile_only("exercises/modules/modules1.rs")?;
|
||||
compile_only("exercises/modules/modules2.rs")?;
|
||||
compile_only("exercises/macros/macros1.rs")?;
|
||||
compile_only("exercises/macros/macros2.rs")?;
|
||||
compile_only("exercises/macros/macros3.rs")?;
|
||||
compile_only("exercises/macros/macros4.rs")?;
|
||||
compile_only("exercises/test4.rs")?;
|
||||
compile_only("exercises/move_semantics/move_semantics1.rs")?;
|
||||
compile_only("exercises/move_semantics/move_semantics2.rs")?;
|
||||
compile_only("exercises/move_semantics/move_semantics3.rs")?;
|
||||
compile_only("exercises/move_semantics/move_semantics4.rs")?;
|
||||
test("exercises/error_handling/errors1.rs")?;
|
||||
test("exercises/error_handling/errors2.rs")?;
|
||||
test("exercises/error_handling/errors3.rs")?;
|
||||
test("exercises/error_handling/errorsn.rs")?;
|
||||
compile_only("exercises/error_handling/option1.rs")?;
|
||||
test("exercises/error_handling/result1.rs")?;
|
||||
compile_only("exercises/threads/threads1.rs")?;
|
||||
pub fn verify<'a>(start_at: impl IntoIterator<Item=&'a Exercise>) -> Result<(), ()> {
|
||||
for exercise in start_at {
|
||||
match exercise.mode {
|
||||
Mode::Test => test(&exercise)?,
|
||||
Mode::Compile => compile_only(&exercise)?,
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn compile_only(filename: &str) -> Result<(), ()> {
|
||||
let bar = ProgressBar::new_spinner();
|
||||
bar.set_message(format!("Compiling {}...", filename).as_str());
|
||||
bar.enable_steady_tick(100);
|
||||
let compilecmd = Command::new("rustc")
|
||||
.args(&[filename, "-o", "temp", "--color", "always"])
|
||||
.output()
|
||||
.expect("fail");
|
||||
bar.finish_and_clear();
|
||||
if compilecmd.status.success() {
|
||||
fn compile_only(exercise: &Exercise) -> Result<(), ()> {
|
||||
let progress_bar = ProgressBar::new_spinner();
|
||||
progress_bar.set_message(format!("Compiling {}...", exercise).as_str());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
let compile_output = exercise.compile();
|
||||
progress_bar.finish_and_clear();
|
||||
if compile_output.status.success() {
|
||||
let formatstr = format!(
|
||||
"{} Successfully compiled {}!",
|
||||
Emoji("✅", "✓"),
|
||||
filename
|
||||
exercise
|
||||
);
|
||||
println!("{}", style(formatstr).green());
|
||||
clean();
|
||||
exercise.clean();
|
||||
Ok(())
|
||||
} else {
|
||||
let formatstr = format!(
|
||||
"{} Compilation of {} failed! Compiler error message:\n",
|
||||
Emoji("⚠️ ", "!"),
|
||||
filename
|
||||
exercise
|
||||
);
|
||||
println!("{}", style(formatstr).red());
|
||||
println!("{}", String::from_utf8_lossy(&compilecmd.stderr));
|
||||
clean();
|
||||
println!("{}", String::from_utf8_lossy(&compile_output.stderr));
|
||||
exercise.clean();
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test(filename: &str) -> Result<(), ()> {
|
||||
let bar = ProgressBar::new_spinner();
|
||||
bar.set_message(format!("Testing {}...", filename).as_str());
|
||||
bar.enable_steady_tick(100);
|
||||
let testcmd = Command::new("rustc")
|
||||
.args(&["--test", filename, "-o", "temp", "--color", "always"])
|
||||
.output()
|
||||
.expect("fail");
|
||||
if testcmd.status.success() {
|
||||
bar.set_message(format!("Running {}...", filename).as_str());
|
||||
let runcmd = Command::new("./temp").output().expect("fail");
|
||||
bar.finish_and_clear();
|
||||
pub fn test(exercise: &Exercise) -> Result<(), ()> {
|
||||
let progress_bar = ProgressBar::new_spinner();
|
||||
progress_bar.set_message(format!("Testing {}...", exercise).as_str());
|
||||
progress_bar.enable_steady_tick(100);
|
||||
|
||||
let compile_output = exercise.compile();
|
||||
if compile_output.status.success() {
|
||||
progress_bar.set_message(format!("Running {}...", exercise).as_str());
|
||||
|
||||
let runcmd = exercise.run();
|
||||
progress_bar.finish_and_clear();
|
||||
|
||||
if runcmd.status.success() {
|
||||
let formatstr = format!("{} Successfully tested {}!", Emoji("✅", "✓"), filename);
|
||||
let formatstr = format!("{} Successfully tested {}!", Emoji("✅", "✓"), exercise);
|
||||
println!("{}", style(formatstr).green());
|
||||
clean();
|
||||
exercise.clean();
|
||||
Ok(())
|
||||
} else {
|
||||
let formatstr = format!(
|
||||
"{} Testing of {} failed! Please try again. Here's the output:",
|
||||
Emoji("⚠️ ", "!"),
|
||||
filename
|
||||
exercise
|
||||
);
|
||||
println!("{}", style(formatstr).red());
|
||||
println!("{}", String::from_utf8_lossy(&runcmd.stdout));
|
||||
clean();
|
||||
exercise.clean();
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
bar.finish_and_clear();
|
||||
progress_bar.finish_and_clear();
|
||||
let formatstr = format!(
|
||||
"{} Compiling of {} failed! Please try again. Here's the output:",
|
||||
Emoji("⚠️ ", "!"),
|
||||
filename
|
||||
exercise
|
||||
);
|
||||
println!("{}", style(formatstr).red());
|
||||
println!("{}", String::from_utf8_lossy(&testcmd.stderr));
|
||||
clean();
|
||||
println!("{}", String::from_utf8_lossy(&compile_output.stderr));
|
||||
exercise.clean();
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
3
tests/fixture/failure/compFailure.rs
Normal file
3
tests/fixture/failure/compFailure.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
let
|
||||
}
|
||||
2
tests/fixture/failure/compNoExercise.rs
Normal file
2
tests/fixture/failure/compNoExercise.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
fn main() {
|
||||
}
|
||||
7
tests/fixture/failure/info.toml
Normal file
7
tests/fixture/failure/info.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
[[exercises]]
|
||||
path = "compFailure.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "testFailure.rs"
|
||||
mode = "test"
|
||||
4
tests/fixture/failure/testFailure.rs
Normal file
4
tests/fixture/failure/testFailure.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
#[test]
|
||||
fn passing() {
|
||||
asset!(true);
|
||||
}
|
||||
2
tests/fixture/success/compSuccess.rs
Normal file
2
tests/fixture/success/compSuccess.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
fn main() {
|
||||
}
|
||||
7
tests/fixture/success/info.toml
Normal file
7
tests/fixture/success/info.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
[[exercises]]
|
||||
path = "compSuccess.rs"
|
||||
mode = "compile"
|
||||
|
||||
[[exercises]]
|
||||
path = "testSuccess.rs"
|
||||
mode = "test"
|
||||
4
tests/fixture/success/testSuccess.rs
Normal file
4
tests/fixture/success/testSuccess.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
#[test]
|
||||
fn passing() {
|
||||
assert!(true);
|
||||
}
|
||||
97
tests/integration_tests.rs
Normal file
97
tests/integration_tests.rs
Normal file
@@ -0,0 +1,97 @@
|
||||
use assert_cmd::prelude::*;
|
||||
use std::process::Command;
|
||||
|
||||
#[test]
|
||||
fn runs_without_arguments() {
|
||||
let mut cmd = Command::cargo_bin("rustlings").unwrap();
|
||||
cmd.assert().success();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fails_when_in_wrong_dir() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.current_dir("tests/")
|
||||
.assert()
|
||||
.code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_all_success() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.arg("v")
|
||||
.current_dir("tests/fixture/success")
|
||||
.assert()
|
||||
.success();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn verify_all_failure() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.arg("v")
|
||||
.current_dir("tests/fixture/failure")
|
||||
.assert()
|
||||
.code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_single_compile_success() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["r", "compSuccess.rs"])
|
||||
.current_dir("tests/fixture/success/")
|
||||
.assert()
|
||||
.success();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_single_compile_failure() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["r", "compFailure.rs"])
|
||||
.current_dir("tests/fixture/failure/")
|
||||
.assert()
|
||||
.code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_single_test_success() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["r", "testSuccess.rs"])
|
||||
.current_dir("tests/fixture/success/")
|
||||
.assert()
|
||||
.success();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_single_test_failure() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["r", "testFailure.rs"])
|
||||
.current_dir("tests/fixture/failure/")
|
||||
.assert()
|
||||
.code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_single_test_no_filename() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.arg("r")
|
||||
.current_dir("tests/fixture/")
|
||||
.assert()
|
||||
.code(1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_single_test_no_exercise() {
|
||||
Command::cargo_bin("rustlings")
|
||||
.unwrap()
|
||||
.args(&["r", "compNoExercise.rs"])
|
||||
.current_dir("tests/fixture/failure")
|
||||
.assert()
|
||||
.code(1);
|
||||
}
|
||||
Reference in New Issue
Block a user