From c4f0bf260c62e150b9539353eecef4ed41cabe6a Mon Sep 17 00:00:00 2001 From: "Hernan G. Gonzalez" Date: Mon, 18 Nov 2024 10:31:02 -0300 Subject: [PATCH] Init --- .github/workflows/pull_request.yml | 55 +++ .gitignore | 3 + Cargo.lock | 559 +++++++++++++++++++++++++++++ Cargo.toml | 30 ++ Course.toml | 2 + Gemfile | 3 + LICENSE | 21 ++ README.md | 54 +++ book.toml | 12 + book/SUMMARY.md | 10 + book/contrib.md | 3 + book/intro.md | 26 ++ book/stage0.md | 13 + book/stage1.md | 20 ++ book/stage2.md | 22 ++ book/stage3.md | 41 +++ book/stage4.md | 35 ++ book/stage5.md | 21 ++ run_tests.rb | 28 ++ src/main.rs | 3 + test_dir/.hidden_file | 0 test_dir/file_with_extension.txt | 0 test_dir/not_hidden_file | 1 + test_dir/not_hidden_file_symlink | 1 + tests/helpers/mod.rs | 26 ++ tests/stage0.rs | 16 + tests/stage1.rs | 26 ++ tests/stage2.rs | 29 ++ tests/stage3.rs | 46 +++ tests/stage4.rs | 37 ++ tests/stage5.rs | 49 +++ upgrade_stage.rb | 16 + 32 files changed, 1208 insertions(+) create mode 100644 .github/workflows/pull_request.yml create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 Course.toml create mode 100644 Gemfile create mode 100644 LICENSE create mode 100644 README.md create mode 100644 book.toml create mode 100644 book/SUMMARY.md create mode 100644 book/contrib.md create mode 100644 book/intro.md create mode 100644 book/stage0.md create mode 100644 book/stage1.md create mode 100644 book/stage2.md create mode 100644 book/stage3.md create mode 100644 book/stage4.md create mode 100644 book/stage5.md create mode 100644 run_tests.rb create mode 100644 src/main.rs create mode 100644 test_dir/.hidden_file create mode 100644 test_dir/file_with_extension.txt create mode 100644 test_dir/not_hidden_file create mode 120000 test_dir/not_hidden_file_symlink create mode 100644 tests/helpers/mod.rs create mode 100644 tests/stage0.rs create mode 100644 tests/stage1.rs create mode 100644 tests/stage2.rs create mode 100644 tests/stage3.rs create mode 100644 tests/stage4.rs create mode 100644 tests/stage5.rs create mode 100644 upgrade_stage.rb diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000..41dac27 --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,55 @@ +name: Pull Request + +on: + pull_request: + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + permissions: write-all + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.1' + - name: Install gems + run: bundle install + - name: Config Changes not allowed + uses: xalvarez/prevent-file-change-action@v1 + with: + githubToken: ${{ secrets.GITHUB_TOKEN }} + pattern: .*\.toml + - name: Test Changes not allowed + uses: xalvarez/prevent-file-change-action@v1 + with: + githubToken: ${{ secrets.GITHUB_TOKEN }} + pattern: tests/* + - name: Format + run: cargo fmt --verbose + - name: Lint + run: cargo clippy --verbose + - name: Build + run: cargo build --verbose + - name: Run Unit Tests + run: cargo test --verbose + - name: Run Stage tests + run: bundle exec ruby run_tests.rb + - name: Upgrade Stage + run: bundle exec ruby upgrade_stage.rb + - uses: stefanzweifel/git-auto-commit-action@v5 + with: + file_pattern: '*.toml' + - name: Congratulations + uses: actions/github-script@v7 + with: + script: | + // Get a list of all issues created by the PR opener + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `Felicitaciones! Completaste el nivel 💪🏼` + }) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6c14190 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +/book/build +Gemfile.lock \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..3bddbb3 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,559 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "bytes" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "oxidar-ls" +version = "0.1.0" +dependencies = [ + "anyhow", + "bytes", + "clap", + "rstest", + "thiserror", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + +[[package]] +name = "rstest" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a2c585be59b6b5dd66a9d2084aa1d8bd52fbdb806eafdeffb52791147862035" +dependencies = [ + "futures", + "futures-timer", + "rstest_macros", + "rustc_version", +] + +[[package]] +name = "rstest_macros" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "825ea780781b15345a146be27eaefb05085e337e869bff01b4306a4fd4a9ad5a" +dependencies = [ + "cfg-if", + "glob", + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version", + "syn", + "unicode-ident", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..e8e6062 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "oxidar-ls" +version = "0.1.0" +authors = [ + "Alejandro ", + "Hernan ", + "Nicolas ", +] +edition = "2021" +description = "A tiny version of ls command" + +[dependencies] +anyhow = "1.0" +bytes = "1.3" +clap = { version = "4.5.20", features = ["derive"] } +thiserror = "1.0" + +[dev-dependencies] +rstest = "0.23.0" + +[lints.rust] +unsafe_code = "forbid" + +[features] +stage0 = [] +stage1 = ["stage0"] +stage2 = ["stage1"] +stage3 = ["stage2"] +stage4 = ["stage3"] +stage5 = ["stage4"] diff --git a/Course.toml b/Course.toml new file mode 100644 index 0000000..69f0b2f --- /dev/null +++ b/Course.toml @@ -0,0 +1,2 @@ +[test] +level = '0' diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..1d7768e --- /dev/null +++ b/Gemfile @@ -0,0 +1,3 @@ +source "https://rubygems.org" + +gem 'toml-rb' \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..74372a4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Oxidar Group + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..7952f32 --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +# Oxidar +¡Bienvenido a **Oxidar**! El objetivo de este curso es aprender Rust creando un proyecto desde cero. El curso está dividido en varias etapas donde iremos agregando nuevas funcionalidades al proyecto, cada una introduciendo un nuevo concepto o un desafío con lo que ya se vio hasta el momento. + +## Herramientas + +### cargo + +`cargo` es el gestor de paquetes de Rust. Además de gestionar los paquetes, con `cargo` podemos correr tests, construir el proyecto y ejecutar nuestro programa. Los comandos que más utilizaremos son: + +- `cargo run -- `: Corre el proyecto pasando como argumentos ``. +- `cargo test`: Corre los tests. +- `cargo add `: Agrega al `Cargo.toml` la dependencia `` + +It then expects to receive a "Hello Rust!" on the standard output. + +### crates.io + +[crates.io](https://crates.io) es el sitio donde se alojan todos los crates públicos o herramientas de líneas de comando que podemos utilizar para construir nuestro proyecto. Generalmente cuando necesitamos una dependencia la solemos buscar aquí. + +En esta página no sólo encontraremos el listado de crates disponibles para utilizar. También encontraremos documentación de los crates (si el autor se molestó en crearla) y su código de fuente. + +### clippy + +`clippy` es el linter oficial de Rust. Esta herramienta nos sirve para marcar potenciales errores y estilar el código de forma correcta. + +### rust-analizer + +[rust-analizer](https://rust-analyzer.github.io/) es una implementación del [Languange Server Protocol](https://microsoft.github.io/language-server-protocol/) para Rust. El mismo nos provee auto-completado de código entre otras cosas útiles para hacer nuestra vida un poco más sencilla. + +### Visual Studio Code + +Visual Studio Code tiene gran soporte para Rust. + +Te recomendamos instalarte los siguientes plug-ins: +- [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer) + > El mejor amigo de todos los rustaceans. Te va a recomendar mejores practicas, detectar patrones y darte explicaciones de como hacer tu codigo más idiomatico. +- [Even Better TOML](https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml) + > Highlight y formatting para el formato de configuraciones más usado por la comunidad. +- [Dependi](https://marketplace.visualstudio.com/items?itemName=fill-labs.dependi) + > Tu compañero para mantener tus dependencias al dia y acceder a su documentación. + + +## Corriendo el proyecto + +Para probar el proyecto, corre `cargo run`. Después de la compilación deberías ver el mensaje `Hello, world!` en la pantalla. + + +Cambia el mensaje a "Hola, Oxidar!" para pasar el primer nivel. + +Exitos! + +## La Guia +El taller esta disponible con [mdbook](https://rust-lang.github.io/mdBook/guide/installation.html), para correlo localmente puedes ejecutar +```mdbook serve``` \ No newline at end of file diff --git a/book.toml b/book.toml new file mode 100644 index 0000000..804b683 --- /dev/null +++ b/book.toml @@ -0,0 +1,12 @@ +[book] +title = "Oxidar LS" +description = "Taller guiado para la programación Rust" +authors = [ + "Alejandro ", + "Hernan ", + "Nicolas ", +] +src = "book" + +[build] +build-dir = "book/build" diff --git a/book/SUMMARY.md b/book/SUMMARY.md new file mode 100644 index 0000000..93f193a --- /dev/null +++ b/book/SUMMARY.md @@ -0,0 +1,10 @@ + + +- [Intro](intro.md) +- [Etapa 0](stage0.md) +- [Etapa 1](stage1.md) +- [Etapa 2](stage2.md) +- [Etapa 3](stage3.md) +- [Etapa 4](stage3.md) +- [Etapa 5](stage3.md) +- [Contribuir](contrib.md) \ No newline at end of file diff --git a/book/contrib.md b/book/contrib.md new file mode 100644 index 0000000..60e0f0e --- /dev/null +++ b/book/contrib.md @@ -0,0 +1,3 @@ +# Contribuir + +Si quieres contribuir, no dudes en crear un issue en nuestro GitHub, o enviarnos un Pull Request con tus mejoras. Muchas gracias! \ No newline at end of file diff --git a/book/intro.md b/book/intro.md new file mode 100644 index 0000000..3244599 --- /dev/null +++ b/book/intro.md @@ -0,0 +1,26 @@ +# Intro + +¡Bienvenido a **Oxidar**! El objetivo de este curso es aprender Rust creando un proyecto desde cero. El curso está dividido en varias etapas donde iremos agregando nuevas funcionalidades al proyecto, cada una introduciendo un nuevo concepto o un desafío con lo que ya se vio hasta el momento. + +## Oxidar LS +En este desafio deberas crear tu propia implementacion del commando `ls`. Vas a empezar con una implementacion sin argumentos y luego le iras sumando mas features a tu proyecto. Luego pudes usarlo para operar en tu propia consola! + +### Avanzar al siguiente nivel +En todos los casos los tests corren de acuerdo al nivel en el que estás en el desafio. Solo haz un commit de tus cambios, envia el push a tu repositorio, y crea un Pull Request para que pasen los tests. El action te avisar del exito o te indicará qué pruebas aún no están verificados. Si todas ellas concluyen correctamente, verás el mensaje de exito al final request. + +También notaras que hay un commit adicional, allí se actualizará el nivel para que te evalue la siguiente etapa :). + + +## Etapas +El taler esta dividio en etapas que van agregando un nuevo desafio sobre lo que implementaste en el paso anterior. Los tests se van sumando, y vamos a chequear que no tengas regresiones ;) + +## Lecturas Recomendadas +Los siguiente son libros fundamentales para todo Rustacean. Te recomendamos que los mantengas de referencia en un acceso rápido. + +El libro de cabecera de todo Rust! +* [The Book](https://doc.rust-lang.org/book/) + +Guia de pequeños ejercicios interactivos. +* [Rustlinks](https://rustlings.cool) + +Hora de oxidar! \ No newline at end of file diff --git a/book/stage0.md b/book/stage0.md new file mode 100644 index 0000000..db6257c --- /dev/null +++ b/book/stage0.md @@ -0,0 +1,13 @@ +## Etapa 0 +Este paso es solo para comprobar que tienes un ambiente actualizado y puedes comenzar el desafio. + +Debes clonar este repositorio y corregir el mensaje que se imprime en la consola a `Hola Oxidar!`. +```rust + println!("Hola Rustacean!"); +``` + +Haz el cambio y pushea al repositorio. Veras que los tests corren, y te notificará que completaste tu primer paso. Nos vemos en el próximo nivel! + +## Lecturas Recomendadas +Para completar este ejercicio, te recomendamos que te familiarices con: +* [println!](https://doc.rust-lang.org/std/macro.println.html) diff --git a/book/stage1.md b/book/stage1.md new file mode 100644 index 0000000..2b7a72c --- /dev/null +++ b/book/stage1.md @@ -0,0 +1,20 @@ +# Etapa 1 +Bienvenido al primer nivel para oxidar `ls`! + +Aquí necesitaras acceder a tus primeras funciones de la standard library y vas a poder los resultados en la consola. Recuerda que es un clon de la herramienta, vas a poder usarlo en tus proyectos y al terminar extenderlo como tu quieras. + +## Cómo pasar el nivel + +Debes imprimir en consola la lista de archivos que encuentres en el directorio donde se ejecute. En este nivel no debes aplicar ningun formato, u información adicional. Eso llegará más adelante ;) + +El tester de este nivel nuestro tester ejecutará la version GNU de `/bin/ls`, sin argumentos, para comparar el standard output. La comparación idéntica será la validacion del nivel. + +Exitos! + +## Lecturas Recomendadas +Para completar este ejercicio, te recomendamos que te familiarices con: +* [std::process::Command](https://doc.rust-lang.org/std/process/struct.Command.html) + +Aquí encontrarás importante entender un concepto clave de Rust, el ownership! +* [Ownership](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html) + diff --git a/book/stage2.md b/book/stage2.md new file mode 100644 index 0000000..b793c68 --- /dev/null +++ b/book/stage2.md @@ -0,0 +1,22 @@ +# Etapa 2 +Bienvenido al segundo nivel para oxidar `ls`! + +Aquí necesitaras interpretar los argumentos con los que es ejecutado tu programa y deberas extender el listado original para incluir aquellos archivos ocultos que `ls` no muestra por defecto. + +## Cómo pasar el nivel + +Debes imprimir en consola la lista de archivos que encuentres en el directorio donde se ejecute. Incluido los **ocultos**! + +El tester de este nivel ejecutara tu comando con los argumentos: +* `-a` +* `--all` + +Ambos argumentso deben dar el mismo resultado. Debes listar los archivos del directorio, sin informacion adicional, e incluir aquellos archivos que son ocultos por defecto. + +Nuevamente nuestro tester ejecutará la version GNU de `/bin/ls`, con los mismos argumentos, para comparar el standard output. La comparación idéntica será la validacion del nivel. + +Exitos! + +## Lecturas Recomendadas +Para completar este ejercicio, te recomendamos que te familiarices con: +* [Command Line Arguments](https://doc.rust-lang.org/book/ch12-01-accepting-command-line-arguments.html) diff --git a/book/stage3.md b/book/stage3.md new file mode 100644 index 0000000..546431b --- /dev/null +++ b/book/stage3.md @@ -0,0 +1,41 @@ +# Etapa 3 +Bienvenido al tercer nivel para oxidar `ls`! + +Aquí necesitaras interpretar aún más argumentos con y deberas empezar a dar formato al listado de archivos. Te pediremos que incluyas datos adicionales sobre sus atributos. + +## Cómo pasar el nivel + +Debes imprimir en consola la lista de archivos que encuentres en el directorio donde se ejecute. No olvides incluir los **ocultos**, si el argumento es enviado. Las pruebas son acumulativas ;) + +Los nuevos argumentos que te enviaremos son los siguientes: +* `-l`: lista los archivos en formato largo. +* `-F`: incluye in indicador de directorio `/` al nombre del archivo +* `-h`: indica el tamaño del archivo en un formato humano. + +Para ver un ejemplo completo, te recomendamos ejecutar el commando completo de GNU `/bin/ls -alFh`. +``` +drwxrwxrwt 14 root wheel 448B Nov 18 09:36 ./ +drwxr-xr-x 6 root wheel 192B Nov 18 08:50 ../ +drwx------ 3 hernangonzalez wheel 96B Nov 18 08:56 TemporaryDirectory.FzPK1P/ +drwx------ 3 hernangonzalez wheel 96B Nov 18 08:56 TemporaryDirectory.JwxVCQ/ +drwx------ 3 hernangonzalez wheel 96B Nov 18 08:56 TemporaryDirectory.M4jDdl/ +drwx------ 3 hernangonzalez wheel 96B Nov 18 08:56 TemporaryDirectory.cF328d/ +drwx------ 3 hernangonzalez wheel 96B Nov 18 09:36 TemporaryDirectory.fBLE6X/ +drwx------ 3 hernangonzalez wheel 96B Nov 18 08:56 TemporaryDirectory.saTlk1/ +drwx------ 3 hernangonzalez wheel 96B Nov 18 09:36 TemporaryDirectory.xHIr98/ +drwx------ 3 hernangonzalez wheel 96B Nov 18 08:56 TemporaryDirectory.yheAih/ +drwx------ 3 hernangonzalez wheel 96B Nov 18 08:50 com.apple.launchd.B95BeBAprb/ +-rw-r--r-- 1 hernangonzalez wheel 0B Nov 18 08:52 hisory.log +drwxr-xr-x 2 root wheel 64B Nov 18 08:50 powerlog/ +drwx------ 2 root wheel 64B Nov 18 08:50 tmp-mount-iN7AQ3/ +``` + +_No te preocupes, no evaluaremos todas las columnas en este ejercicio. Solo aquellas que fueron pedidas en el argumento que te indicamos._ + +Exitos! + +## Lecturas Recomendadas +Para completar este ejercicio, te recomendamos que te familiarices con: +* [Arreglos en Rust](https://doc.rust-lang.org/book/ch08-01-vectors.html) +* [Slice](https://doc.rust-lang.org/book/ch04-03-slices.html#the-slice-type) +* [Display](https://doc.rust-lang.org/std/fmt/trait.Display.html) diff --git a/book/stage4.md b/book/stage4.md new file mode 100644 index 0000000..49a3731 --- /dev/null +++ b/book/stage4.md @@ -0,0 +1,35 @@ +# Etapa 4 +Bienvenido al cuarto nivel para oxidar `ls`! + +En este nivel ayudaras a tus usuarios a usar tu herramienta! Es importante que siempre que construyas una aplicación para la linea de comandos, que incluyas una breve ayuda de como debe ser usado. + +## Cómo pasar el nivel + +Debes imprimir en consola la lista un texto de ayuda con la indicacion de que argumentos soportas y como debe ser ejecutado. No te olvides que las pruebas son acumulativas ;) + +El tester correra tu aplicación con el siguiente argumento: +* `--help`: imprime la ayuda de tu herramienta. + +El resultado esperado el siguiente texto de ayuda: +``` +"A tiny version of ls command + +Usage: oxidar-ls [OPTIONS] + +Arguments: + Path to list + +Options: + -a, --all Show hidden files + -F, --format Format file names. Appendds a symbol at the end indicating the type of file. Slash ('/') is for directories and at sign ('@') is for symbolic links + -l, --list Show the files in a list + -h, --human Show the file size in a human-redable format + --help +``` + +Exitos! + +## Lecturas Recomendadas +Para completar este ejercicio, te recomendamos que te familiarices con: +* [Manejo de Errores](https://doc.rust-lang.org/book/ch09-00-error-handling.html) +* [Clap](https://docs.rs/clap/latest/clap/) diff --git a/book/stage5.md b/book/stage5.md new file mode 100644 index 0000000..a13d61f --- /dev/null +++ b/book/stage5.md @@ -0,0 +1,21 @@ +# Etapa 5 +Bienvenido al quinto nivel para oxidar `ls`! + +En este nivel sumarás un nuevo indicador a tus columnas para conocer el nivel de acceso de cada archivo listado. + +## Cómo pasar el nivel + +Debes imprimir en consola la lista de archivos que encuentres en el directorio donde se ejecute incluyendo el codigo de acceso (octeto) de cada archivo. No olvides incluir los **ocultos**, las pruebas son acumulativas ;) + +El resultado esperado debe incluir el nivel de acceso como a continuación: +``` +drwxr-xr-x +``` + +_No te preocupes, no evaluaremos todas las columnas en este ejercicio. Solo aquellas que fueron pedidas en el argumento que te indicamos._ + +Exitos! + +## Lecturas Recomendadas +Para completar este ejercicio, te recomendamos que te familiarices con: +* [From](https://doc.rust-lang.org/std/convert/trait.From.html) diff --git a/run_tests.rb b/run_tests.rb new file mode 100644 index 0000000..500e630 --- /dev/null +++ b/run_tests.rb @@ -0,0 +1,28 @@ +require 'toml-rb' + +# Helper functions +def ensure_build + system "cargo build --release" + if $?.exitstatus != 0 + puts "Oops, we could not build the project!" + exit 1 + end +end + +def select_stage + path = File.join(File.dirname(__FILE__), 'Course.toml') + toml_data = TomlRB.load_file(path) + return toml_data['test']['level'] +end + +# Build the project +puts "Building the project..." +ensure_build + +# Run the tests +puts "Running tests..." +stage = select_stage +system "cargo test --release --features stage#{stage}" + +# Congrats! +puts "All Done!" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..88416ad --- /dev/null +++ b/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hola Rustacean!"); +} diff --git a/test_dir/.hidden_file b/test_dir/.hidden_file new file mode 100644 index 0000000..e69de29 diff --git a/test_dir/file_with_extension.txt b/test_dir/file_with_extension.txt new file mode 100644 index 0000000..e69de29 diff --git a/test_dir/not_hidden_file b/test_dir/not_hidden_file new file mode 100644 index 0000000..4effa19 --- /dev/null +++ b/test_dir/not_hidden_file @@ -0,0 +1 @@ +hello! diff --git a/test_dir/not_hidden_file_symlink b/test_dir/not_hidden_file_symlink new file mode 120000 index 0000000..59d1b04 --- /dev/null +++ b/test_dir/not_hidden_file_symlink @@ -0,0 +1 @@ +not_hidden_file \ No newline at end of file diff --git a/tests/helpers/mod.rs b/tests/helpers/mod.rs new file mode 100644 index 0000000..c485eab --- /dev/null +++ b/tests/helpers/mod.rs @@ -0,0 +1,26 @@ +#![allow(dead_code)] + +/// Splits the outbut by space, newline, tab or null characters +pub fn split_ls_output(output: &[u8]) -> Vec<&str> { + std::str::from_utf8(output) + .expect("unable to convert to text /bin/ls output") + .split([' ', '\n', '\t', '\0']) + .filter(|s| !s.is_empty()) + .collect::>() +} + +pub fn split_ls_column_output<'a, T: Into<&'a str>>(output: T) -> Vec<&'a str> { + let string = output.into(); + string + .split([' ', '\n', '\t', '\0']) + .filter(|s| !s.is_empty()) + .collect::>() +} + +pub fn split_ls_output_by_newline(output: &[u8]) -> Vec<&str> { + std::str::from_utf8(output) + .expect("unable to convert to text /bin/ls output") + .split('\n') + .filter(|s| !s.is_empty()) + .collect::>() +} diff --git a/tests/stage0.rs b/tests/stage0.rs new file mode 100644 index 0000000..f27d8eb --- /dev/null +++ b/tests/stage0.rs @@ -0,0 +1,16 @@ +#![cfg(feature = "stage0")] +use std::process::Command; + +#[test] +fn test_stage_0() { + let output = Command::new("./target/debug/oxidar-ls") + .args(["./test_dir"]) + .output() + .expect("failed to execute process"); + + assert!(output.status.success()); + assert_eq!( + std::str::from_utf8(&output.stdout).expect("a utf8 string output"), + "Hola Oxidar!\n" + ) +} diff --git a/tests/stage1.rs b/tests/stage1.rs new file mode 100644 index 0000000..1d07a4e --- /dev/null +++ b/tests/stage1.rs @@ -0,0 +1,26 @@ +#![cfg(feature = "stage1")] + +mod helpers; + +use helpers::split_ls_output; +use std::process::Command; + +#[test] +fn test_stage_1() { + let output = Command::new("./target/debug/oxidar-ls") + .args(["./test_dir"]) + .output() + .expect("failed to execute process"); + + let expected = Command::new("/bin/ls") + .args(["./test_dir"]) + .output() + .expect("failed to execute process"); + + assert!(output.status.success()); + + let expected = split_ls_output(&expected.stdout); + let output = split_ls_output(&output.stdout); + + assert_eq!(expected, output); +} diff --git a/tests/stage2.rs b/tests/stage2.rs new file mode 100644 index 0000000..23fd061 --- /dev/null +++ b/tests/stage2.rs @@ -0,0 +1,29 @@ +#![cfg(feature = "stage2")] + +mod helpers; + +use helpers::split_ls_output; +use rstest::rstest; +use std::process::Command; + +#[rstest] +#[case::short_argument("-a")] +#[case::long_argument("--all")] +fn test_stage_2(#[case] ls_argument: &str) { + let output = Command::new("./target/debug/oxidar-ls") + .args([ls_argument, "./test_dir"]) + .output() + .expect("failed to execute process"); + + let expected = Command::new("/bin/ls") + .args(["-a", "./test_dir"]) + .output() + .expect("failed to execute process"); + + assert!(output.status.success()); + + let expected = split_ls_output(&expected.stdout); + let output = split_ls_output(&output.stdout); + + assert_eq!(expected, output); +} diff --git a/tests/stage3.rs b/tests/stage3.rs new file mode 100644 index 0000000..73948f8 --- /dev/null +++ b/tests/stage3.rs @@ -0,0 +1,46 @@ +#![cfg(feature = "stage3")] + +mod helpers; + +use helpers::{split_ls_column_output, split_ls_output_by_newline}; +use rstest::rstest; +use std::process::Command; + +#[rstest] +#[case::arguments_l(&["-l"])] +#[case::arguments_lF(&["-l", "-F"])] +#[case::arguments_lFh(&["-l", "-F", "-h"])] +#[case::arguments_lFha(&["-l", "-F", "-h", "-a"])] +fn test_stage_3(#[case] ls_arguments: &[&'static str]) { + let output = Command::new("./target/debug/oxidar-ls") + .args([ls_arguments, &["./test_dir"]].concat()) + .output() + .expect("failed to execute process"); + + let expected = Command::new("/bin/ls") + .args([ls_arguments, &["./test_dir"]].concat()) + .output() + .expect("failed to execute process"); + + assert!(output.status.success()); + + let expected_lines = split_ls_output_by_newline(&expected.stdout); + let output_lines = split_ls_output_by_newline(&output.stdout); + + // We use expected_lines[1..] because the first element in the /bin/ls output is the total + // column + assert_eq!(expected_lines[1..].len(), output_lines.len()); + + for (expected, output) in expected_lines[1..].iter().zip(output_lines) { + let expected = split_ls_column_output(*expected); + let output = split_ls_column_output(&*output); + // Assert size + // We ignore the . and ../ directories on purpose because is not that easy to calculate + // their size + if output[1] != "." && output[1] != "./" && output[1] != ".." && output[1] != "../" { + assert_eq!(expected[4], output[0]); + } + // Assert name + assert_eq!(expected[8], output[1]); + } +} diff --git a/tests/stage4.rs b/tests/stage4.rs new file mode 100644 index 0000000..151744f --- /dev/null +++ b/tests/stage4.rs @@ -0,0 +1,37 @@ +#![cfg(feature = "stage4")] + +mod helpers; + +use rstest::rstest; +use std::process::Command; + +const EXPECTED_HELP_TEXT: &str = r#"A tiny version of ls command + +Usage: oxidar-ls [OPTIONS] + +Arguments: + Path to list + +Options: + -a, --all Show hidden files + -F, --format Format file names. Appendds a symbol at the end indicating the type of file. Slash ('/') is for directories and at sign ('@') is for symbolic links + -l, --list Show the files in a list + -h, --human Show the file size in a human-redable format + --help +"#; + +#[rstest] +#[case::arguments_help(&["--help"])] +fn test_stage_4(#[case] ls_arguments: &[&'static str]) { + let output = Command::new("./target/debug/oxidar-ls") + .args([ls_arguments, &["./test_dir"]].concat()) + .output() + .expect("failed to execute process"); + + assert!(output.status.success()); + + assert_eq!( + EXPECTED_HELP_TEXT, + std::str::from_utf8(&output.stdout).unwrap() + ); +} diff --git a/tests/stage5.rs b/tests/stage5.rs new file mode 100644 index 0000000..a017b71 --- /dev/null +++ b/tests/stage5.rs @@ -0,0 +1,49 @@ +#![cfg(feature = "stage5")] + +mod helpers; + +use helpers::{split_ls_column_output, split_ls_output_by_newline}; +use rstest::rstest; +use std::process::Command; + +#[rstest] +#[case::arguments_l(&["-l"])] +#[case::arguments_lF(&["-l", "-F"])] +#[case::arguments_lFh(&["-l", "-F", "-h"])] +#[case::arguments_lFha(&["-l", "-F", "-h", "-a"])] +#[case::arguments_lFha(&["-lFha"])] // This tests tha clap was introduced and works as expected +fn test_stage_5(#[case] ls_arguments: &[&'static str]) { + let output = Command::new("./target/debug/oxidar-ls") + .args([ls_arguments, &["./test_dir"]].concat()) + .output() + .expect("failed to execute process"); + + let expected = Command::new("/bin/ls") + .args([ls_arguments, &["./test_dir"]].concat()) + .output() + .expect("failed to execute process"); + + assert!(output.status.success()); + + let expected_lines = split_ls_output_by_newline(&expected.stdout); + let output_lines = split_ls_output_by_newline(&output.stdout); + + // We use expected_lines[1..] because the first element in the /bin/ls output is the total + // column + assert_eq!(expected_lines[1..].len(), output_lines.len()); + + for (expected, output) in expected_lines[1..].iter().zip(output_lines) { + let expected = split_ls_column_output(*expected); + let output = split_ls_column_output(&*output); + // Assert permissions + assert_eq!(expected[0], output[0]); + + // We ignore the . and ../ directories on purpose because is not that easy to calculate + // their size + if output[2] != "." && output[2] != "./" && output[2] != ".." && output[2] != "../" { + assert_eq!(expected[4], output[1]); + } + // Assert name + assert_eq!(expected[8], output[2]); + } +} diff --git a/upgrade_stage.rb b/upgrade_stage.rb new file mode 100644 index 0000000..d5057d8 --- /dev/null +++ b/upgrade_stage.rb @@ -0,0 +1,16 @@ +require 'toml-rb' + +# Load the toml file +path = File.join(File.dirname(__FILE__), 'Course.toml') +toml_data = TomlRB.load_file(path) + +# Upgrade the stage +stage = toml_data['test']['level'] +next_stage = Integer(stage) + 1 +puts "Upgrading to stage #{next_stage}..." +toml_data['test']['level'] = next_stage.to_s + +# Save the file +data = TomlRB.dump(toml_data) +File.write(path, data) +puts "All done!"