diff --git a/.gitignore b/.gitignore index ff23b2d..5c71db3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ **/target **/*.rs.bk +**/.redo Cargo.lock *.iml *.ipr diff --git a/Cargo.toml b/Cargo.toml index fd3a79c..05e5463 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "macrotest" version = "1.0.9" # remember to update in lib.rs authors = ["eupn "] -edition = "2018" +edition = "2021" rust-version = "1.56" license = "MIT OR Apache-2.0" readme = "README.md" diff --git a/test-virtual/Cargo.toml b/test-virtual/Cargo.toml new file mode 100644 index 0000000..c5724bb --- /dev/null +++ b/test-virtual/Cargo.toml @@ -0,0 +1,33 @@ +[workspace] +resolver = "2" +members = [ + "wrkspc", + "wrkspc-dev", + "wrkspc-macro", + "wrkspc-test", +] + +[workspace.package] +version = "0.0.0" +authors = ["eupn ", "Mark Van de Vyver "] +license = "Apache-2.0" +edition = "2021" +rust-version = "1.56" +description = "A virtual workspace example for macrotest" +homepage = "https://github.com/eupn/macrotest" +repository = "https://github.com/eupn/macrotest" +documentation = "https://docs.rs/macrotest" +readme = "README.md" +publish = false + +[workspace.dependencies] +wrkspc = { path = "wrkspc" } +wrkspc-dev = { path = "wrkspc-dev" } +wrkspc-macro = { path = "wrkspc-macro" } +wrkspc-test = { path = "wrkspc-test" } + +macrotest = { path = "../" } + +proc-macro2 = "1.0" +quote = "1" +syn = "2.0" diff --git a/test-virtual/README.md b/test-virtual/README.md new file mode 100644 index 0000000..999fe60 --- /dev/null +++ b/test-virtual/README.md @@ -0,0 +1,155 @@ +# `test-virtual` + +A convention over configuration template for integration tests of proc-macros, +in a workspace. + +This example workspace contains crates: + +- `wrkspc`: A library crate. +- `wrkspc-dev`: A development crate. +- `wrkspc-macro`: The Proc-macro crate. +- `wrkspc-test`: Integration tests, and DJB's `redo` build system for `wrkspc-macro`. + +Where: + +- `wrkspc`: A "Hello world" style library (for release as a crate). +- `wrkspc-dev`: A "Hello world" style library for development (not for release). +- `wrkspc-macro`: The `test-promacro-project` adjusted to fit into the workspace plugin-test harness. This crate provides a declarative `test_vec![]` macro +to test its expansion under the [tests](tests) directory with [`macrostest`](https://crates.io/crates/macrotest). +- `wrkspc-test`: The `test-project` adjusted to fit into the workspace integrated test harness. + +The integration test harness, `wkspc-test`, uses [DJB's redo build system](https://cr.yp.to/redo.html), as implemented by [apenwarr](https://github.com/apenwarr/redo/) and as ported to Rust by [zombiezen](https://github.com/zombiezen/redo-rs). + +In this build process `all.do` flows to a generic build step `default.do`. Hence, `all.do` is responsible for iterating over all source files and `default.do` is responsible for processing each individual file. The `default.do` is kept generic by adhering to some naming conventions, shared between the macro and test crates: + +In this setup: + +- `all.do` is the starting point of the build process. +- `default.do` is called by `all.do` for each source file. +- `default.do` processes each file by: + - Extracting the filename from the path using `basename`, resulting in `bin`. + - Removing the `.expanded.rs` extension using `cut`, resulting in `bin`. + +The next diagram shows the flow of data in the files between the folders `wkspc-macro` and `wkspc-test`: + +- `wkspc-macro` is the source directory containing the `.rs` to be tested files. +- `all.do` processes each `.rs` file in `wkspc-macro`. +- `default.expand.do` is called by `all.do` for each `.rs` file and generates a corresponding `.expanded.rs` file if the source file has changed. +- The `.expanded.rs` files are placed in the `wkspc-test` directory. +- If redoing the expanded file fails, it records the error message. +- If the build succeeds, it removes `exp_file.staged`. + +[Build data flow](./images/figure-data.png) +|Source .rs files| B[all.do] + B -->|Processes each file| C[default.expand.do] + C -->|Generates .expanded.rs files if source file has changed| D[wkspc-test] + D -->|If redo fails| E[Records error message] + E --> F[error_messages] + D -->|If build succeeds| G[Removes exp_file.staged] +--> + +Here's a Mermaid diagram that shows how the build process in `all.do` flows to `default.expand.do` and then to `default.do`. In this first diagram: + +- `all.do` is the starting point of the build process. +- `default.expand.do` is called by `all.do` for each source file. +- `default.expand.do` processes each file by: + - Extracting the filename from the path using `basename`, resulting in `bin_file`. + - Removing the `.expanded.rs` extension using `cut`, resulting in `bin_name`. + - Checking if the .expanded.rs file exists. If it does, it continues processing. If it doesn't, it skips the file. + - Getting the relative path of the source file using `realpath`, resulting in `rel_path`. + - Constructing the path of the expanded file using string concatenation, resulting in `expanded_path`. + - Checking if the source file has changed. If it has, it redoes the expanded file. If it hasn't, it skips the file. + - If redoing the expanded file fails, it increments the error count and records the error message. +- `default.do` is called for each file that is not skipped. + - It copies the source file to the destination, resulting in `exp_file.staged`. + - It builds the file using `cargo build`. If the build succeeds, it removes `exp_file.staged`. + +[Build logic flow](./images/figure-logic.png) +|Iterates over all source files| B[default.expand.do] + B --> C{Processes each file} + C -->|1. Extracts filename from path| D[Uses basename] + D --> E[bin_file] + C -->|2. Removes .expanded.rs extension| F[Uses cut] + F --> G[bin_name] + C -->|3. Checks if .expanded.rs file exists| H[If file exists] + H -->|Yes| I[Continues processing] + I -->|4. Gets relative path of source file| J[Uses realpath] + J --> K[rel_path] + I -->|5. Constructs path of expanded file| L[Uses string concatenation] + L --> M[expanded_path] + I -->|6. Checks if source file has changed| N[If file has changed] + N -->|Yes| O[Redoes expanded file] + O -->|If redo fails| P[Increments error count and records error message] + P --> Q[error_count and error_messages] + N -->|No| R[Skips file] + R --> S[default.do] + S -->|7. Copies source file to destination| T[Uses cp] + T --> U[exp_file.staged] + S -->|8. Builds with cargo| V[Uses cargo build] + V -->|If build succeeds| W[Removes exp_file.staged] +--> + +## Containers + +To run Testcontainers-based tests, +you need a Docker-API compatible container runtime, +such as using [Testcontainers Cloud](https://www.testcontainers.cloud/) or installing [Podman](https://podman.io/) or Docker locally. [Testcontainers Desktop](https://testcontainers.com/desktop/) takes care of most of the manual configuration for alternative runtimes. See [Customizing Docker host detection](#customizing-docker-host-detection) for general configuration mechanisms. + +### Podman + +In order to run testcontainers against [podman](https://podman.io/) the env vars bellow should be set + +MacOS: + +```bash +{% raw %} +export DOCKER_HOST=unix://$(podman machine inspect --format '{{.ConnectionInfo.PodmanSocket.Path}}') +export TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE=/var/run/docker.sock +{% endraw %} +``` + +Linux: + +```bash +export DOCKER_HOST=unix://${XDG_RUNTIME_DIR}/podman/podman.sock +``` + +If you're running Podman in rootless mode, ensure to include the following line to disable Ryuk: + +```bash +export TESTCONTAINERS_RYUK_DISABLED=true +``` + +!!! note + Previous to version 1.19.0, `export TESTCONTAINERS_RYUK_PRIVILEGED=true` + was required for rootful mode. Starting with 1.19.0, this is no longer required. + +### Container environment discovery + +Testcontainers will try to connect to a Docker daemon using the following strategies in order: + +- Environment variables: + - `DOCKER_HOST` + - `DOCKER_TLS_VERIFY` + - `DOCKER_CERT_PATH` +- Defaults: + - `DOCKER_HOST=https://localhost:2376` + - `DOCKER_TLS_VERIFY=1` + - `DOCKER_CERT_PATH=~/.docker` +- If Docker Machine is installed, the docker machine environment for the *first* machine found. Docker Machine needs to be on the PATH for this to succeed. +- If you're going to run your tests inside a container, please read [Patterns for running tests inside a docker container](continuous_integration/dind_patterns.md) first. + +### Docker registry authentication + +Testcontainers will try to authenticate to registries with supplied config using the following strategies in order: + +- Environment variables: + - `DOCKER_AUTH_CONFIG` +- Docker config + - At location specified in `DOCKER_CONFIG` or at `{HOME}/.docker/config.json` + +### Customizing Docker host detection diff --git a/test-virtual/TESTCONTAINERS.md b/test-virtual/TESTCONTAINERS.md new file mode 100644 index 0000000..a6fccc4 --- /dev/null +++ b/test-virtual/TESTCONTAINERS.md @@ -0,0 +1,137 @@ +# [Custom configuration](https://github.com/testcontainers/testcontainers-java/blob/main/docs/features/configuration.md) + +You can override some default properties if your environment requires that. + +## Configuration locations + +The configuration will be loaded from multiple locations. Properties are considered in the following order: + +1. Environment variables +2. `.testcontainers.properties` in user's home folder. Example locations: +**Linux:** `/home/myuser/.testcontainers.properties` +**Windows:** `C:/Users/myuser/.testcontainers.properties` +**macOS:** `/Users/myuser/.testcontainers.properties` +3. `testcontainers.properties` on the classpath. + +Note that when using environment variables, configuration property names should be set in upper +case with underscore separators, preceded by `TESTCONTAINERS_` - e.g. `checks.disable` becomes +`TESTCONTAINERS_CHECKS_DISABLE`. + +The classpath `testcontainers.properties` file may exist within the local codebase (e.g. within the `src/test/resources` directory) or within library dependencies that you may have. +Any such configuration files will have their contents merged. +If any keys conflict, the value will be taken on the basis of the first value found in: + +* 'local' classpath (i.e. where the URL of the file on the classpath begins with `file:`), then +* other classpath locations (i.e. JAR files) - considered in _alphabetical order of path_ to provide deterministic ordering. + +## Disabling the startup checks +> +> **checks.disable = [true|false]** + +Before running any containers Testcontainers will perform a set of startup checks to ensure that your environment is configured correctly. Usually they look like this: + +``` + ℹ︎ Checking the system... + ✔ Docker version should be at least 1.6.0 + ✔ File should be mountable + ✔ A port exposed by a docker container should be accessible +``` + +It takes a couple of seconds, but if you want to speed up your tests, you can disable the checks once you have everything configured. Add `checks.disable=true` to your `$HOME/.testcontainers.properties` to completely disable them. + +## Customizing images + +!!! note + This approach is discouraged and deprecated, but is documented for completeness. + Overriding individual image names via configuration may be removed in 2021. + See [Image Name Substitution](./image_name_substitution.md) for other strategies for substituting image names to pull from other registries. + +Testcontainers uses public Docker images to perform different actions like startup checks, VNC recording and others. +Some companies disallow the usage of Docker Hub, but you can override `*.image` properties with your own images from your private registry to workaround that. + +> **ryuk.container.image = testcontainers/ryuk:0.3.3** +> Performs fail-safe cleanup of containers, and always required (unless [Ryuk is disabled](#disabling-ryuk)) + +> **tinyimage.container.image = alpine:3.16** +> Used to check whether images can be pulled at startup, and always required (unless [startup checks are disabled](#disabling-the-startup-checks)) + +> **sshd.container.image = testcontainers/sshd:1.1.0** +> Required if [exposing host ports to containers](./networking.md#exposing-host-ports-to-the-container) + +> **vncrecorder.container.image = testcontainers/vnc-recorder:1.3.0** +> Used by VNC recorder in Testcontainers' Selenium integration + +> **socat.container.image = alpine/socat** +> **compose.container.image = docker/compose:1.8.0** +> Required if using [Docker Compose](../modules/docker_compose.md) + +> **kafka.container.image = confluentinc/cp-kafka** +> Used by KafkaContainer + +> **localstack.container.image = localstack/localstack** +> Used by LocalStack + +> **pulsar.container.image = apachepulsar/pulsar:2.2.0** +> Used by Apache Pulsar + +## Customizing Ryuk resource reaper + +> **ryuk.container.image = testcontainers/ryuk:0.3.3** +> The resource reaper is responsible for container removal and automatic cleanup of dead containers at JVM shutdown + +> **ryuk.container.privileged = true** +> In some environments ryuk must be started in privileged mode to work properly (--privileged flag) + +### Disabling Ryuk + +Ryuk must be started as a privileged container. +If your environment already implements automatic cleanup of containers after the execution, +but does not allow starting privileged containers, you can turn off the Ryuk container by setting +`TESTCONTAINERS_RYUK_DISABLED` **environment variable** to `true`. + +!!!tip + Note that Testcontainers will continue doing the cleanup at JVM's shutdown, unless you `kill -9` your JVM process. + +## Customizing image pull behaviour + +> **pull.pause.timeout = 30** +> By default Testcontainers will abort the pull of an image if the pull appears stalled (no data transferred) for longer than this duration (in seconds). + +## Customizing client ping behaviour + +> **client.ping.timeout = 5** +> Specifies for how long Testcontainers will try to connect to the Docker client to obtain valid info about the client before giving up and trying next strategy, if applicable (in seconds). + +## Customizing Docker host detection + +Testcontainers will attempt to detect the Docker environment and configure everything to work automatically. + +However, sometimes customization is required. Testcontainers will respect the following **environment variables**: + +> **DOCKER_HOST** = unix:///var/run/docker.sock +> See [Docker environment variables](https://docs.docker.com/engine/reference/commandline/cli/#environment-variables) +> +> **TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE** +> Path to Docker's socket. Used by Ryuk, Docker Compose, and a few other containers that need to perform Docker actions. +> Example: `/var/run/docker-alt.sock` +> +> **TESTCONTAINERS_HOST_OVERRIDE** +> Docker's host on which ports are exposed. +> Example: `docker.svc.local` + +For advanced users, the Docker host connection can be configured **via configuration** in `~/.testcontainers.properties`. +Note that these settings require use of the `EnvironmentAndSystemPropertyClientProviderStrategy`. The example below +illustrates usage: + +```properties +docker.client.strategy=org.testcontainers.dockerclient.EnvironmentAndSystemPropertyClientProviderStrategy +docker.host=tcp\://my.docker.host\:1234 # Equivalent to the DOCKER_HOST environment variable. Colons should be escaped. +docker.tls.verify=1 # Equivalent to the DOCKER_TLS_VERIFY environment variable +docker.cert.path=/some/path # Equivalent to the DOCKER_CERT_PATH environment variable +``` + +In addition, you can deactivate this behaviour by specifying: + +```properties +dockerconfig.source=autoIgnoringUserProperties # 'auto' by default +``` diff --git a/test-virtual/images/figure-data.png b/test-virtual/images/figure-data.png new file mode 100644 index 0000000..6768227 Binary files /dev/null and b/test-virtual/images/figure-data.png differ diff --git a/test-virtual/images/figure-logic.png b/test-virtual/images/figure-logic.png new file mode 100644 index 0000000..df9d32e Binary files /dev/null and b/test-virtual/images/figure-logic.png differ diff --git a/test-virtual/wrkspc-dev/Cargo.toml b/test-virtual/wrkspc-dev/Cargo.toml new file mode 100644 index 0000000..31c84ec --- /dev/null +++ b/test-virtual/wrkspc-dev/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "wrkspc-dev" +version.workspace = true +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +description.workspace = true +documentation.workspace = true +homepage.workspace = true +repository.workspace = true +license.workspace = true +readme.workspace = true +publish = false + +[dependencies] +wrkspc-macro.workspace = true +# inventory.workspace = true +macrotest.workspace = true diff --git a/test-virtual/wrkspc-dev/src/lib.rs b/test-virtual/wrkspc-dev/src/lib.rs new file mode 100644 index 0000000..2e6a5a8 --- /dev/null +++ b/test-virtual/wrkspc-dev/src/lib.rs @@ -0,0 +1,5 @@ +pub use wrkspc_macro::*; + +pub fn hello() { + println!("Hello Developer World!") +} diff --git a/test-virtual/wrkspc-dev/tests/lib.rs b/test-virtual/wrkspc-dev/tests/lib.rs new file mode 100644 index 0000000..ead8d3b --- /dev/null +++ b/test-virtual/wrkspc-dev/tests/lib.rs @@ -0,0 +1,4 @@ +#[test] +fn wrkspc_test() { + assert_eq!("equal", "equal") +} diff --git a/test-virtual/wrkspc-macro/.gitignore b/test-virtual/wrkspc-macro/.gitignore new file mode 100644 index 0000000..6936990 --- /dev/null +++ b/test-virtual/wrkspc-macro/.gitignore @@ -0,0 +1,3 @@ +/target +**/*.rs.bk +Cargo.lock diff --git a/test-virtual/wrkspc-macro/Cargo.toml b/test-virtual/wrkspc-macro/Cargo.toml new file mode 100644 index 0000000..3d4b9a6 --- /dev/null +++ b/test-virtual/wrkspc-macro/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "wrkspc-macro" +version.workspace = true +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +description.workspace = true +documentation.workspace = true +homepage.workspace = true +repository.workspace = true +license.workspace = true +readme.workspace = true +publish= false + +[lib] +proc-macro = true + +[dependencies] +proc-macro2.workspace = true +quote.workspace = true +syn.workspace = true + +# wrkspc-test dependencies become dev-dependencies +[dev-dependencies] +wrkspc-dev.workspace = true +# wrkspc-test.workspace = true + +macrotest.workspace = true diff --git a/test-virtual/wrkspc-macro/src/lib.rs b/test-virtual/wrkspc-macro/src/lib.rs new file mode 100644 index 0000000..9716db7 --- /dev/null +++ b/test-virtual/wrkspc-macro/src/lib.rs @@ -0,0 +1,50 @@ +extern crate proc_macro; +use proc_macro::TokenStream; + +use quote::quote; +use syn::{parse_macro_input, DeriveInput}; + +/// Example of [function-like procedural macro][1]. +/// +/// [1]: https://doc.rust-lang.org/reference/procedural-macros.html#function-like-procedural-macros +#[proc_macro] +pub fn my_macro(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + + let tokens = quote! { + #input + + struct Hello; + }; + + tokens.into() +} + +/// Example of user-defined [derive mode macro][1] +/// +/// [1]: https://doc.rust-lang.org/reference/procedural-macros.html#derive-mode-macros +#[proc_macro_derive(MyDerive)] +pub fn my_derive(_input: TokenStream) -> TokenStream { + // Emit test garbage + let tokens = quote! { + struct Hello; + }; + + tokens.into() +} + +/// Example of user-defined [procedural macro attribute][1]. +/// +/// [1]: https://doc.rust-lang.org/reference/procedural-macros.html#attribute-macros +#[proc_macro_attribute] +pub fn my_attribute(_args: TokenStream, input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + + let tokens = quote! { + #input + + struct Hello; + }; + + tokens.into() +} diff --git a/test-virtual/wrkspc-macro/tests/attribute.rs b/test-virtual/wrkspc-macro/tests/attribute.rs new file mode 100644 index 0000000..6ab6352 --- /dev/null +++ b/test-virtual/wrkspc-macro/tests/attribute.rs @@ -0,0 +1,4 @@ +#[test] +pub fn expansion() { + macrotest::expand("tests/expand/attribute.rs"); +} \ No newline at end of file diff --git a/test-virtual/wrkspc-macro/tests/derive.rs b/test-virtual/wrkspc-macro/tests/derive.rs new file mode 100644 index 0000000..a370553 --- /dev/null +++ b/test-virtual/wrkspc-macro/tests/derive.rs @@ -0,0 +1,4 @@ +#[test] +pub fn expansion() { + macrotest::expand("tests/expand/derive.rs"); +} \ No newline at end of file diff --git a/test-virtual/wrkspc-macro/tests/expand/attribute.expanded.rs b/test-virtual/wrkspc-macro/tests/expand/attribute.expanded.rs new file mode 100644 index 0000000..c37c39c --- /dev/null +++ b/test-virtual/wrkspc-macro/tests/expand/attribute.expanded.rs @@ -0,0 +1,5 @@ +#[macro_use] +extern crate wrkspc_macro; +struct Test; +struct Hello; +fn main() {} diff --git a/test-virtual/wrkspc-macro/tests/expand/attribute.rs b/test-virtual/wrkspc-macro/tests/expand/attribute.rs new file mode 100644 index 0000000..e9d59bd --- /dev/null +++ b/test-virtual/wrkspc-macro/tests/expand/attribute.rs @@ -0,0 +1,7 @@ +#[macro_use] +extern crate wrkspc_macro; + +#[my_attribute] +struct Test; + +fn main() {} \ No newline at end of file diff --git a/test-virtual/wrkspc-macro/tests/expand/derive.expanded.rs b/test-virtual/wrkspc-macro/tests/expand/derive.expanded.rs new file mode 100644 index 0000000..5a24c70 --- /dev/null +++ b/test-virtual/wrkspc-macro/tests/expand/derive.expanded.rs @@ -0,0 +1,5 @@ +#[macro_use] +extern crate wrkspc_macro; +struct Test; +struct Hello; +fn main() {} \ No newline at end of file diff --git a/test-virtual/wrkspc-macro/tests/expand/derive.rs b/test-virtual/wrkspc-macro/tests/expand/derive.rs new file mode 100644 index 0000000..245d871 --- /dev/null +++ b/test-virtual/wrkspc-macro/tests/expand/derive.rs @@ -0,0 +1,5 @@ +#[macro_use] +extern crate wrkspc_macro; +#[derive(MyDerive)] +struct Test; +fn main() {} \ No newline at end of file diff --git a/test-virtual/wrkspc-macro/tests/expand/macro.expanded.rs b/test-virtual/wrkspc-macro/tests/expand/macro.expanded.rs new file mode 100644 index 0000000..b48da90 --- /dev/null +++ b/test-virtual/wrkspc-macro/tests/expand/macro.expanded.rs @@ -0,0 +1,6 @@ +#[macro_use] +extern crate wrkspc_macro; +pub fn main() { + struct Test; + struct Hello; +} diff --git a/test-virtual/wrkspc-macro/tests/expand/macro.rs b/test-virtual/wrkspc-macro/tests/expand/macro.rs new file mode 100644 index 0000000..856c198 --- /dev/null +++ b/test-virtual/wrkspc-macro/tests/expand/macro.rs @@ -0,0 +1,6 @@ +#[macro_use] +extern crate wrkspc_macro; + +pub fn main() { + my_macro! { struct Test; } +} diff --git a/test-virtual/wrkspc-macro/tests/macro.rs b/test-virtual/wrkspc-macro/tests/macro.rs new file mode 100644 index 0000000..7effd6f --- /dev/null +++ b/test-virtual/wrkspc-macro/tests/macro.rs @@ -0,0 +1,4 @@ +#[test] +pub fn expansion() { + macrotest::expand("tests/expand/macro.rs"); +} \ No newline at end of file diff --git a/test-virtual/wrkspc-test/.gitignore b/test-virtual/wrkspc-test/.gitignore new file mode 100644 index 0000000..5d09ab4 --- /dev/null +++ b/test-virtual/wrkspc-test/.gitignore @@ -0,0 +1,3 @@ +**/target +**/*.rs.bk +**/.redo diff --git a/test-virtual/wrkspc-test/Cargo.toml b/test-virtual/wrkspc-test/Cargo.toml new file mode 100644 index 0000000..1eb5041 --- /dev/null +++ b/test-virtual/wrkspc-test/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "wrkspc-test" +edition = "2021" + +publish = false + +[features] +default = [] + +[dependencies] +wrkspc-macro = { path = "../wrkspc-macro" } + +[dev-dependencies] + +# Staged files are managed by the redo build system scripts. +# After a successful build the .staged extension is removed. +[[bin]] +name = "attribute" +path = "src/tests/expand/attribute.expanded.rs.staged" +[[bin]] +name = "derive" +path = "src/tests/expand/derive.expanded.rs.staged" +[[bin]] +name = "macro" +path = "src/tests/expand/macro.expanded.rs.staged" diff --git a/test-virtual/wrkspc-test/all.do b/test-virtual/wrkspc-test/all.do new file mode 100644 index 0000000..5ab0c34 --- /dev/null +++ b/test-virtual/wrkspc-test/all.do @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +exec >&2 + +MACRO_DIR="test-virtual/wrkspc-macro" + +REPO_DIR=$(git rev-parse --show-toplevel) +DEST_DIR="${REPO_DIR}/test-virtual/wrkspc-test/src/tests" + +mkdir -p target + +# Find .do files, exclude certain ones, remove .do extension, and call redo-ifchange +find . -maxdepth 6 -type f -name '*.do' | \ + grep -vE 'default\.do|all\.do|default\.expand\.do' | \ + sed -r 's/\.do$//' | \ + xargs redo-ifchange + +# Find all .rs files not ending in .expanded.rs +find "${REPO_DIR}/${MACRO_DIR}/tests" -type f -name "*.rs" ! -name "*.expanded.rs" -print0 | while IFS= read -r -d '' file; do + source_file="${file%.rs}.expanded.rs" + + # Check if there is a corresponding .expanded.rs file + if [ ! -f "$source_file" ]; then + continue + fi + + redo-ifchange "${source_file}" + + test_name=$(basename "${file}" | cut -f 1 -d '.') + + # Invoke virtual target for test_name + redo-ifchange "${test_name}.expand" + + # Get the relative path of the source file + rel_path=$(realpath --relative-to="${REPO_DIR}/${MACRO_DIR}/tests" "$file") + expanded_file="${rel_path%.rs}.expanded.rs" + expanded_path="${DEST_DIR}/${expanded_file}" + + # Fall back to the default.do script + if ! redo-ifchange "${expanded_path}"; then + printf "Error in file: %s\n" "${source_file}" >&2 + exit 1 + fi +done \ No newline at end of file diff --git a/test-virtual/wrkspc-test/default.do b/test-virtual/wrkspc-test/default.do new file mode 100644 index 0000000..0fafc6a --- /dev/null +++ b/test-virtual/wrkspc-test/default.do @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +exec >&2 + +MACRO_DIR="test-virtual/wrkspc-macro" + +# Define the source and destination directories +REPO_DIR=$(git rev-parse --show-toplevel) +SRC_DIR="${REPO_DIR}/${MACRO_DIR}" +DEST_DIR="${REPO_DIR}/test-virtual/wrkspc-test" + +exp_file="${DEST_DIR}/$1" +src_file="${SRC_DIR}/$(realpath --relative-to="${DEST_DIR}/src" "$exp_file")" + +# Get the filename without the extension +bin_name=$(basename "$exp_file" | cut -f 1 -d '.') + +# redo when the expanded file changes +redo-ifchange "${src_file}" + +# Check if source file exists and copy it to the destination +if [ -e "${src_file}" ]; then + cp --force "${src_file}" "${exp_file}.staged" + cat "${src_file}" >"$3" +else + echo "$0: Fatal: don't know how to build '$1'" >&2 + exit 99 +fi + +# Build and log +if cargo build --release --bin "${bin_name}" > "target/zno-test-build-${bin_name}.log" 2>&1; then + rm --force "${exp_file}.staged" +fi \ No newline at end of file diff --git a/test-virtual/wrkspc-test/default.expand.do b/test-virtual/wrkspc-test/default.expand.do new file mode 100644 index 0000000..013c389 --- /dev/null +++ b/test-virtual/wrkspc-test/default.expand.do @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +exec >&2 + +MACRO_DIR="test-virtual/wrkspc-macro" + +REPO_DIR=$(git rev-parse --show-toplevel) +SRC_DIR="${REPO_DIR}/${MACRO_DIR}" + +test_name="${1%.*}" + +# Run the test and log the output +cargo test --test "${test_name}" --manifest-path ${SRC_DIR}/Cargo.toml > "target/zno-test-expansion-${test_name}.log" 2>&1 + +# If the newly produced file disappears, we need to redo. +redo-ifchange "${SRC_DIR}/tests/expand/${test_name}.rs" diff --git a/test-virtual/wrkspc-test/src/tests/expand/attribute.expanded.rs b/test-virtual/wrkspc-test/src/tests/expand/attribute.expanded.rs new file mode 100644 index 0000000..c37c39c --- /dev/null +++ b/test-virtual/wrkspc-test/src/tests/expand/attribute.expanded.rs @@ -0,0 +1,5 @@ +#[macro_use] +extern crate wrkspc_macro; +struct Test; +struct Hello; +fn main() {} diff --git a/test-virtual/wrkspc-test/src/tests/expand/derive.expanded.rs b/test-virtual/wrkspc-test/src/tests/expand/derive.expanded.rs new file mode 100644 index 0000000..5a24c70 --- /dev/null +++ b/test-virtual/wrkspc-test/src/tests/expand/derive.expanded.rs @@ -0,0 +1,5 @@ +#[macro_use] +extern crate wrkspc_macro; +struct Test; +struct Hello; +fn main() {} \ No newline at end of file diff --git a/test-virtual/wrkspc-test/src/tests/expand/macro.expanded.rs b/test-virtual/wrkspc-test/src/tests/expand/macro.expanded.rs new file mode 100644 index 0000000..b48da90 --- /dev/null +++ b/test-virtual/wrkspc-test/src/tests/expand/macro.expanded.rs @@ -0,0 +1,6 @@ +#[macro_use] +extern crate wrkspc_macro; +pub fn main() { + struct Test; + struct Hello; +} diff --git a/test-virtual/wrkspc/Cargo.toml b/test-virtual/wrkspc/Cargo.toml new file mode 100644 index 0000000..68dc4a8 --- /dev/null +++ b/test-virtual/wrkspc/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "wrkspc" +version.workspace = true +authors.workspace = true +edition.workspace = true +rust-version.workspace = true +description.workspace = true +documentation.workspace = true +homepage.workspace = true +repository.workspace = true +license.workspace = true +readme.workspace = true +publish = false + + +[dependencies] +wrkspc-dev.workspace = true +wrkspc-macro.workspace = true +wrkspc-test.workspace = true + +macrotest.workspace = true + +# inventory.workspace = true +proc-macro2.workspace = true +quote.workspace = true +syn.workspace = true diff --git a/test-virtual/wrkspc/src/lib.rs b/test-virtual/wrkspc/src/lib.rs new file mode 100644 index 0000000..2c73804 --- /dev/null +++ b/test-virtual/wrkspc/src/lib.rs @@ -0,0 +1,5 @@ +pub use wrkspc_macro::*; + +pub fn hello() { + println!("Hello World!") +} diff --git a/test-virtual/wrkspc/tests/lib.rs b/test-virtual/wrkspc/tests/lib.rs new file mode 100644 index 0000000..ead8d3b --- /dev/null +++ b/test-virtual/wrkspc/tests/lib.rs @@ -0,0 +1,4 @@ +#[test] +fn wrkspc_test() { + assert_eq!("equal", "equal") +}