[INFO] updating cached repository https://github.com/schmijos/cucumber-rust-reprod [INFO] running `"git" "-c" "credential.helper=" "-c" "credential.helper=/workspace/cargo-home/bin/git-credential-null" "-c" "remote.origin.fetch=refs/heads/*:refs/heads/*" "fetch" "origin" "--force" "--prune"` [INFO] running `"git" "rev-parse" "HEAD"` [INFO] [stdout] cfa2d75e05fb5af2122a507b79fa18a5b344e376 [INFO] testing schmijos/cucumber-rust-reprod against 1.44.0 for beta-1.45-1 [INFO] running `"git" "clone" "/workspace/cache/git-repos/https%3A%2F%2Fgithub.com%2Fschmijos%2Fcucumber-rust-reprod" "/workspace/builds/worker-5/source"` [INFO] [stderr] Cloning into '/workspace/builds/worker-5/source'... [INFO] [stderr] done. [INFO] validating manifest of git repo https://github.com/schmijos/cucumber-rust-reprod on toolchain 1.44.0 [INFO] running `"/workspace/cargo-home/bin/cargo" "+1.44.0" "read-manifest" "--manifest-path" "Cargo.toml"` [INFO] started tweaking git repo https://github.com/schmijos/cucumber-rust-reprod [INFO] removed 0 missing tests [INFO] finished tweaking git repo https://github.com/schmijos/cucumber-rust-reprod [INFO] tweaked toml for git repo https://github.com/schmijos/cucumber-rust-reprod written to /workspace/builds/worker-5/source/Cargo.toml [INFO] crate git repo https://github.com/schmijos/cucumber-rust-reprod already has a lockfile, it will not be regenerated [INFO] running `"/workspace/cargo-home/bin/cargo" "+1.44.0" "fetch" "--locked" "--manifest-path" "Cargo.toml"` [INFO] running `"docker" "create" "-v" "/var/lib/crater-agent-workspace/builds/worker-5/target:/opt/rustwide/target:rw,Z" "-v" "/var/lib/crater-agent-workspace/builds/worker-5/source:/opt/rustwide/workdir:ro,Z" "-v" "/var/lib/crater-agent-workspace/cargo-home:/opt/rustwide/cargo-home:ro,Z" "-v" "/var/lib/crater-agent-workspace/rustup-home:/opt/rustwide/rustup-home:ro,Z" "-e" "SOURCE_DIR=/opt/rustwide/workdir" "-e" "MAP_USER_ID=0" "-e" "CARGO_TARGET_DIR=/opt/rustwide/target" "-e" "CARGO_INCREMENTAL=0" "-e" "RUST_BACKTRACE=full" "-e" "RUSTFLAGS=--cap-lints=warn" "-e" "CARGO_HOME=/opt/rustwide/cargo-home" "-e" "RUSTUP_HOME=/opt/rustwide/rustup-home" "-w" "/opt/rustwide/workdir" "-m" "1610612736" "--network" "none" "rustops/crates-build-env" "/opt/rustwide/cargo-home/bin/cargo" "+1.44.0" "build" "--frozen"` [INFO] [stderr] WARNING: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap. [INFO] [stdout] ab96f88e7e0e9348a231868c5effbba753942b169a4be1b9ed19b596a0a72408 [INFO] running `"docker" "start" "-a" "ab96f88e7e0e9348a231868c5effbba753942b169a4be1b9ed19b596a0a72408"` [INFO] [stderr] sudo: setrlimit(RLIMIT_CORE): Operation not permitted [INFO] [stderr] Compiling cucumber-test v0.1.0 (/opt/rustwide/workdir) [INFO] [stderr] Finished dev [unoptimized + debuginfo] target(s) in 0.84s [INFO] running `"docker" "inspect" "ab96f88e7e0e9348a231868c5effbba753942b169a4be1b9ed19b596a0a72408"` [INFO] running `"docker" "rm" "-f" "ab96f88e7e0e9348a231868c5effbba753942b169a4be1b9ed19b596a0a72408"` [INFO] [stdout] ab96f88e7e0e9348a231868c5effbba753942b169a4be1b9ed19b596a0a72408 [INFO] running `"docker" "create" "-v" "/var/lib/crater-agent-workspace/builds/worker-5/target:/opt/rustwide/target:rw,Z" "-v" "/var/lib/crater-agent-workspace/builds/worker-5/source:/opt/rustwide/workdir:ro,Z" "-v" "/var/lib/crater-agent-workspace/cargo-home:/opt/rustwide/cargo-home:ro,Z" "-v" "/var/lib/crater-agent-workspace/rustup-home:/opt/rustwide/rustup-home:ro,Z" "-e" "SOURCE_DIR=/opt/rustwide/workdir" "-e" "MAP_USER_ID=0" "-e" "CARGO_TARGET_DIR=/opt/rustwide/target" "-e" "CARGO_INCREMENTAL=0" "-e" "RUST_BACKTRACE=full" "-e" "RUSTFLAGS=--cap-lints=warn" "-e" "CARGO_HOME=/opt/rustwide/cargo-home" "-e" "RUSTUP_HOME=/opt/rustwide/rustup-home" "-w" "/opt/rustwide/workdir" "-m" "1610612736" "--network" "none" "rustops/crates-build-env" "/opt/rustwide/cargo-home/bin/cargo" "+1.44.0" "test" "--frozen" "--no-run"` [INFO] [stderr] WARNING: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap. [INFO] [stdout] f7ffa2d77cdf5b98f3c1be8ad3ac59bb09ad2f8501eefa49b042e086cdf68682 [INFO] running `"docker" "start" "-a" "f7ffa2d77cdf5b98f3c1be8ad3ac59bb09ad2f8501eefa49b042e086cdf68682"` [INFO] [stderr] sudo: setrlimit(RLIMIT_CORE): Operation not permitted [INFO] [stderr] Compiling syn v0.15.44 [INFO] [stderr] Compiling syn v1.0.13 [INFO] [stderr] Compiling pathdiff v0.1.0 [INFO] [stderr] Compiling globset v0.4.4 [INFO] [stderr] Compiling term_size v0.3.1 [INFO] [stderr] Compiling shh v1.0.0 [INFO] [stderr] Compiling textwrap v0.11.0 [INFO] [stderr] Compiling clap v2.33.0 [INFO] [stderr] Compiling ignore v0.4.11 [INFO] [stderr] Compiling globwalk v0.7.1 [INFO] [stderr] Compiling pest_generator v2.1.1 [INFO] [stderr] Compiling pest_derive v2.1.0 [INFO] [stderr] Compiling darling_core v0.9.0 [INFO] [stderr] Compiling darling_macro v0.9.0 [INFO] [stderr] Compiling darling v0.9.0 [INFO] [stderr] Compiling derive_builder_core v0.5.0 [INFO] [stderr] Compiling derive_builder v0.7.2 [INFO] [stderr] Compiling gherkin_rust v0.6.0 [INFO] [stderr] Compiling cucumber_rust v0.6.4 [INFO] [stderr] Compiling cucumber-test v0.1.0 (/opt/rustwide/workdir) [INFO] [stderr] warning: unused import: `steps` [INFO] [stderr] --> tests/cucumber.rs:1:26 [INFO] [stderr] | [INFO] [stderr] 1 | use cucumber::{cucumber, steps, before, after}; [INFO] [stderr] | ^^^^^ [INFO] [stderr] | [INFO] [stderr] = note: `#[warn(unused_imports)]` on by default [INFO] [stderr] [INFO] [stderr] warning: unused variable: `scenario` [INFO] [stderr] --> tests/cucumber.rs:65:25 [INFO] [stderr] | [INFO] [stderr] 65 | before!(a_before_fn => |scenario| { [INFO] [stderr] | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_scenario` [INFO] [stderr] | [INFO] [stderr] = note: `#[warn(unused_variables)]` on by default [INFO] [stderr] [INFO] [stderr] warning: unused variable: `scenario` [INFO] [stderr] --> tests/cucumber.rs:70:24 [INFO] [stderr] | [INFO] [stderr] 70 | after!(an_after_fn => |scenario| { [INFO] [stderr] | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_scenario` [INFO] [stderr] [INFO] [stderr] warning: unused variable: `step` [INFO] [stderr] --> tests/cucumber.rs:23:50 [INFO] [stderr] | [INFO] [stderr] 23 | given "I am trying out Cucumber" |world, step| { [INFO] [stderr] | ^^^^ help: if this is intentional, prefix it with an underscore: `_step` [INFO] [stderr] [INFO] [stderr] warning: unused variable: `step` [INFO] [stderr] --> tests/cucumber.rs:28:51 [INFO] [stderr] | [INFO] [stderr] 28 | when "I consider what I am doing" |world, step| { [INFO] [stderr] | ^^^^ help: if this is intentional, prefix it with an underscore: `_step` [INFO] [stderr] [INFO] [stderr] warning: unused variable: `step` [INFO] [stderr] --> tests/cucumber.rs:34:48 [INFO] [stderr] | [INFO] [stderr] 34 | then "I am interested in ATDD" |world, step| { [INFO] [stderr] | ^^^^ help: if this is intentional, prefix it with an underscore: `_step` [INFO] [stderr] [INFO] [stderr] warning: unused variable: `world` [INFO] [stderr] --> tests/cucumber.rs:39:55 [INFO] [stderr] | [INFO] [stderr] 39 | then regex r"^we can (.*) rules with regex$" |world, matches, step| { [INFO] [stderr] | ^^^^^ help: if this is intentional, prefix it with an underscore: `_world` [INFO] [stderr] [INFO] [stderr] warning: unused variable: `step` [INFO] [stderr] --> tests/cucumber.rs:39:71 [INFO] [stderr] | [INFO] [stderr] 39 | then regex r"^we can (.*) rules with regex$" |world, matches, step| { [INFO] [stderr] | ^^^^ help: if this is intentional, prefix it with an underscore: `_step` [INFO] [stderr] [INFO] [stderr] warning: unused variable: `world` [INFO] [stderr] --> tests/cucumber.rs:44:77 [INFO] [stderr] | [INFO] [stderr] 44 | then regex r"^we can also match (\d+) (.+) types$" (usize, String) |world, num, word, step| { [INFO] [stderr] | ^^^^^ help: if this is intentional, prefix it with an underscore: `_world` [INFO] [stderr] [INFO] [stderr] warning: unused variable: `step` [INFO] [stderr] --> tests/cucumber.rs:44:95 [INFO] [stderr] | [INFO] [stderr] 44 | then regex r"^we can also match (\d+) (.+) types$" (usize, String) |world, num, word, step| { [INFO] [stderr] | ^^^^ help: if this is intentional, prefix it with an underscore: `_step` [INFO] [stderr] [INFO] [stderr] warning: unused variable: `world` [INFO] [stderr] --> tests/cucumber.rs:50:67 [INFO] [stderr] | [INFO] [stderr] 50 | then "we can use data tables to provide more parameters" |world, step| { [INFO] [stderr] | ^^^^^ help: if this is intentional, prefix it with an underscore: `_world` [INFO] [stderr] [INFO] [stderr] warning: 11 warnings emitted [INFO] [stderr] [INFO] [stderr] Finished test [unoptimized + debuginfo] target(s) in 1m 12s [INFO] running `"docker" "inspect" "f7ffa2d77cdf5b98f3c1be8ad3ac59bb09ad2f8501eefa49b042e086cdf68682"` [INFO] running `"docker" "rm" "-f" "f7ffa2d77cdf5b98f3c1be8ad3ac59bb09ad2f8501eefa49b042e086cdf68682"` [INFO] [stdout] f7ffa2d77cdf5b98f3c1be8ad3ac59bb09ad2f8501eefa49b042e086cdf68682 [INFO] running `"docker" "create" "-v" "/var/lib/crater-agent-workspace/builds/worker-5/target:/opt/rustwide/target:rw,Z" "-v" "/var/lib/crater-agent-workspace/builds/worker-5/source:/opt/rustwide/workdir:ro,Z" "-v" "/var/lib/crater-agent-workspace/cargo-home:/opt/rustwide/cargo-home:ro,Z" "-v" "/var/lib/crater-agent-workspace/rustup-home:/opt/rustwide/rustup-home:ro,Z" "-e" "SOURCE_DIR=/opt/rustwide/workdir" "-e" "MAP_USER_ID=0" "-e" "CARGO_TARGET_DIR=/opt/rustwide/target" "-e" "CARGO_INCREMENTAL=0" "-e" "RUST_BACKTRACE=full" "-e" "RUSTFLAGS=--cap-lints=warn" "-e" "CARGO_HOME=/opt/rustwide/cargo-home" "-e" "RUSTUP_HOME=/opt/rustwide/rustup-home" "-w" "/opt/rustwide/workdir" "-m" "1610612736" "--network" "none" "rustops/crates-build-env" "/opt/rustwide/cargo-home/bin/cargo" "+1.44.0" "test" "--frozen"` [INFO] [stderr] WARNING: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap. [INFO] [stdout] 0db4cc7d5fc449470fb197b3dcb636d1558e90cc066f71722840ecb976ec7e95 [INFO] running `"docker" "start" "-a" "0db4cc7d5fc449470fb197b3dcb636d1558e90cc066f71722840ecb976ec7e95"` [INFO] [stderr] sudo: setrlimit(RLIMIT_CORE): Operation not permitted [INFO] [stderr] warning: unused import: `steps` [INFO] [stderr] --> tests/cucumber.rs:1:26 [INFO] [stderr] | [INFO] [stderr] 1 | use cucumber::{cucumber, steps, before, after}; [INFO] [stderr] | ^^^^^ [INFO] [stderr] | [INFO] [stderr] = note: `#[warn(unused_imports)]` on by default [INFO] [stderr] [INFO] [stderr] warning: unused variable: `scenario` [INFO] [stderr] --> tests/cucumber.rs:65:25 [INFO] [stderr] | [INFO] [stderr] 65 | before!(a_before_fn => |scenario| { [INFO] [stderr] | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_scenario` [INFO] [stderr] | [INFO] [stderr] = note: `#[warn(unused_variables)]` on by default [INFO] [stderr] [INFO] [stderr] warning: unused variable: `scenario` [INFO] [stderr] --> tests/cucumber.rs:70:24 [INFO] [stderr] | [INFO] [stderr] 70 | after!(an_after_fn => |scenario| { [INFO] [stderr] | ^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_scenario` [INFO] [stderr] [INFO] [stderr] warning: unused variable: `step` [INFO] [stderr] --> tests/cucumber.rs:23:50 [INFO] [stderr] | [INFO] [stderr] 23 | given "I am trying out Cucumber" |world, step| { [INFO] [stderr] | ^^^^ help: if this is intentional, prefix it with an underscore: `_step` [INFO] [stderr] [INFO] [stderr] warning: unused variable: `step` [INFO] [stderr] --> tests/cucumber.rs:28:51 [INFO] [stderr] | [INFO] [stderr] 28 | when "I consider what I am doing" |world, step| { [INFO] [stderr] | ^^^^ help: if this is intentional, prefix it with an underscore: `_step` [INFO] [stderr] [INFO] [stderr] warning: unused variable: `step` [INFO] [stderr] --> tests/cucumber.rs:34:48 [INFO] [stderr] | [INFO] [stderr] 34 | then "I am interested in ATDD" |world, step| { [INFO] [stderr] | ^^^^ help: if this is intentional, prefix it with an underscore: `_step` [INFO] [stderr] [INFO] [stderr] warning: unused variable: `world` [INFO] [stderr] --> tests/cucumber.rs:39:55 [INFO] [stderr] | [INFO] [stderr] 39 | then regex r"^we can (.*) rules with regex$" |world, matches, step| { [INFO] [stderr] | ^^^^^ help: if this is intentional, prefix it with an underscore: `_world` [INFO] [stderr] [INFO] [stderr] warning: unused variable: `step` [INFO] [stderr] --> tests/cucumber.rs:39:71 [INFO] [stderr] | [INFO] [stderr] 39 | then regex r"^we can (.*) rules with regex$" |world, matches, step| { [INFO] [stderr] | ^^^^ help: if this is intentional, prefix it with an underscore: `_step` [INFO] [stderr] [INFO] [stderr] warning: unused variable: `world` [INFO] [stderr] --> tests/cucumber.rs:44:77 [INFO] [stderr] | [INFO] [stderr] 44 | then regex r"^we can also match (\d+) (.+) types$" (usize, String) |world, num, word, step| { [INFO] [stderr] | ^^^^^ help: if this is intentional, prefix it with an underscore: `_world` [INFO] [stderr] [INFO] [stderr] warning: unused variable: `step` [INFO] [stderr] --> tests/cucumber.rs:44:95 [INFO] [stderr] | [INFO] [stderr] 44 | then regex r"^we can also match (\d+) (.+) types$" (usize, String) |world, num, word, step| { [INFO] [stderr] | ^^^^ help: if this is intentional, prefix it with an underscore: `_step` [INFO] [stderr] [INFO] [stderr] warning: unused variable: `world` [INFO] [stderr] --> tests/cucumber.rs:50:67 [INFO] [stderr] | [INFO] [stderr] 50 | then "we can use data tables to provide more parameters" |world, step| { [INFO] [stderr] | ^^^^^ help: if this is intentional, prefix it with an underscore: `_world` [INFO] [stderr] [INFO] [stderr] warning: 11 warnings emitted [INFO] [stderr] [INFO] [stderr] Finished test [unoptimized + debuginfo] target(s) in 0.24s [INFO] [stderr] Running /opt/rustwide/target/debug/deps/cucumber_test-adec060b7417734a [INFO] [stdout] [INFO] [stdout] running 0 tests [INFO] [stdout] [INFO] [stdout] test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out [INFO] [stdout] [INFO] [stderr] Running /opt/rustwide/target/debug/deps/cucumber-326b35939ed637f5 [INFO] [stdout] [Cucumber v0.6.4] [INFO] [stdout] [INFO] [stdout] Feature: Camera  features/camera.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: Constructing a camera  features/camera.feature:3:11 [INFO] [stdout]  - Given hsize ← 160  features/camera.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And vsize ← 120  features/camera.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And field_of_view ← π/2  features/camera.feature:6:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When c ← camera(hsize, vsize, field_of_view)  features/camera.feature:7:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c.hsize = 160  features/camera.feature:8:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c.vsize = 120  features/camera.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c.field_of_view = π/2  features/camera.feature:10:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c.transform = identity_matrix  features/camera.feature:11:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The pixel size for a horizontal canvas features/camera.feature:13:11 [INFO] [stdout]  - Given c ← camera(200, 125, π/2)  features/camera.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c.pixel_size = 0.01  features/camera.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The pixel size for a vertical canvas  features/camera.feature:17:11 [INFO] [stdout]  - Given c ← camera(125, 200, π/2)  features/camera.feature:18:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c.pixel_size = 0.01  features/camera.feature:19:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Constructing a ray through the center of the canvas [INFO] [stdout]  features/camera.feature:21:11 [INFO] [stdout]  - Given c ← camera(201, 101, π/2)  features/camera.feature:22:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When r ← ray_for_pixel(c, 100, 50)  features/camera.feature:23:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then r.origin = point(0, 0, 0)  features/camera.feature:24:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r.direction = vector(0, 0, -1)  features/camera.feature:25:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Constructing a ray through a corner of the canvas [INFO] [stdout]  features/camera.feature:27:11 [INFO] [stdout]  - Given c ← camera(201, 101, π/2)  features/camera.feature:28:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When r ← ray_for_pixel(c, 0, 0)  features/camera.feature:29:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then r.origin = point(0, 0, 0)  features/camera.feature:30:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r.direction = vector(0.66519, 0.33259, -0.66851) [INFO] [stdout]  features/camera.feature:31:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Constructing a ray when the camera is transformed [INFO] [stdout]  features/camera.feature:33:11 [INFO] [stdout]  - Given c ← camera(201, 101, π/2)  features/camera.feature:34:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When c.transform ← rotation_y(π/4) * translation(0, -2, 5) [INFO] [stdout]  features/camera.feature:35:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray_for_pixel(c, 100, 50)  features/camera.feature:36:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then r.origin = point(0, 2, -5)  features/camera.feature:37:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r.direction = vector(√2/2, 0, -√2/2)  features/camera.feature:38:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Rendering a world with a camera  features/camera.feature:40:11 [INFO] [stdout]  - Given w ← default_world()  features/camera.feature:41:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c ← camera(11, 11, π/2)  features/camera.feature:42:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And from ← point(0, 0, -5)  features/camera.feature:43:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And to ← point(0, 0, 0)  features/camera.feature:44:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And up ← vector(0, 1, 0)  features/camera.feature:45:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c.transform ← view_transform(from, to, up) features/camera.feature:46:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When image ← render(c, w)  features/camera.feature:47:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then pixel_at(image, 5, 5) = color(0.38066, 0.47583, 0.2855) [INFO] [stdout]  features/camera.feature:48:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: Canvas  features/canvas.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: Creating a canvas  features/canvas.feature:3:11 [INFO] [stdout]  - Given c ← canvas(10, 20)  features/canvas.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c.width = 10  features/canvas.feature:5:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c.height = 20  features/canvas.feature:6:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And every pixel of c is color(0, 0, 0)  features/canvas.feature:7:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Writing pixels to a canvas  features/canvas.feature:9:11 [INFO] [stdout]  - Given c ← canvas(10, 20)  features/canvas.feature:10:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And red ← color(1, 0, 0)  features/canvas.feature:11:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When write_pixel(c, 2, 3, red)  features/canvas.feature:12:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then pixel_at(c, 2, 3) = red  features/canvas.feature:13:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Constructing the PPM header  features/canvas.feature:15:11 [INFO] [stdout]  - Given c ← canvas(5, 3)  features/canvas.feature:16:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When ppm ← canvas_to_ppm(c)  features/canvas.feature:17:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then lines 1-3 of ppm are  features/canvas.feature:18:3 [INFO] [stdout]  """ [INFO] [stdout]  P3 [INFO] [stdout] 5 3 [INFO] [stdout] 255 [INFO] [stdout]  """ [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Constructing the PPM pixel data  features/canvas.feature:25:11 [INFO] [stdout]  - Given c ← canvas(5, 3)  features/canvas.feature:26:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c1 ← color(1.5, 0, 0)  features/canvas.feature:27:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c2 ← color(0, 0.5, 0)  features/canvas.feature:28:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c3 ← color(-0.5, 0, 1)  features/canvas.feature:29:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When write_pixel(c, 0, 0, c1)  features/canvas.feature:30:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And write_pixel(c, 2, 1, c2)  features/canvas.feature:31:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And write_pixel(c, 4, 2, c3)  features/canvas.feature:32:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And ppm ← canvas_to_ppm(c)  features/canvas.feature:33:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then lines 4-6 of ppm are  features/canvas.feature:34:3 [INFO] [stdout]  """ [INFO] [stdout]  255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 [INFO] [stdout] 0 0 0 0 0 0 0 128 0 0 0 0 0 0 0 [INFO] [stdout] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 255 [INFO] [stdout]  """ [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Splitting long lines in PPM files  features/canvas.feature:41:11 [INFO] [stdout]  - Given c ← canvas(10, 2)  features/canvas.feature:42:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When every pixel of c is set to color(1, 0.8, 0.6) [INFO] [stdout]  features/canvas.feature:43:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And ppm ← canvas_to_ppm(c)  features/canvas.feature:44:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then lines 4-7 of ppm are  features/canvas.feature:45:3 [INFO] [stdout]  """ [INFO] [stdout]  255 204 153 255 204 153 255 204 153 255 204 153 255 204 153 255 204 [INFO] [stdout] 153 255 204 153 255 204 153 255 204 153 255 204 153 [INFO] [stdout] 255 204 153 255 204 153 255 204 153 255 204 153 255 204 153 255 204 [INFO] [stdout] 153 255 204 153 255 204 153 255 204 153 255 204 153 [INFO] [stdout]  """ [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: PPM files are terminated by a newline character [INFO] [stdout]  features/canvas.feature:53:11 [INFO] [stdout]  - Given c ← canvas(5, 3)  features/canvas.feature:54:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When ppm ← canvas_to_ppm(c)  features/canvas.feature:55:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then ppm ends with a newline character  features/canvas.feature:56:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: Cones  features/cones.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: Intersecting a cone with a ray 0  features/cones.feature:12:12 [INFO] [stdout]  - Given shape ← cone()  features/cones.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(vector(0, 0, 1))  features/cones.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -5), direction)  features/cones.feature:6:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(shape, r)  features/cones.feature:7:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/cones.feature:8:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = 5  features/cones.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].t = 5  features/cones.feature:10:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a cone with a ray 1  features/cones.feature:12:12 [INFO] [stdout]  - Given shape ← cone()  features/cones.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(vector(1, 1, 1))  features/cones.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -5), direction)  features/cones.feature:6:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(shape, r)  features/cones.feature:7:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/cones.feature:8:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = 8.66025  features/cones.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].t = 8.66025  features/cones.feature:10:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a cone with a ray 2  features/cones.feature:12:12 [INFO] [stdout]  - Given shape ← cone()  features/cones.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(vector(-0.5, -1, 1))  features/cones.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(1, 1, -5), direction)  features/cones.feature:6:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(shape, r)  features/cones.feature:7:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/cones.feature:8:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = 4.55006  features/cones.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].t = 49.44994  features/cones.feature:10:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a cone with a ray parallel to one of its halves [INFO] [stdout]  features/cones.feature:18:11 [INFO] [stdout]  - Given shape ← cone()  features/cones.feature:19:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(vector(0, 1, 1))  features/cones.feature:20:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -1), direction)  features/cones.feature:21:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(shape, r)  features/cones.feature:22:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 1  features/cones.feature:23:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = 0.35355  features/cones.feature:24:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a cone's end caps 0  features/cones.feature:36:12 [INFO] [stdout]  - Given shape ← cone()  features/cones.feature:27:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape.minimum ← -0.5  features/cones.feature:28:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape.maximum ← 0.5  features/cones.feature:29:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape.closed ← true  features/cones.feature:30:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(vector(0, 1, 0))  features/cones.feature:31:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -5), direction)  features/cones.feature:32:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(shape, r)  features/cones.feature:33:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 0  features/cones.feature:34:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a cone's end caps 1  features/cones.feature:36:12 [INFO] [stdout]  - Given shape ← cone()  features/cones.feature:27:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape.minimum ← -0.5  features/cones.feature:28:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape.maximum ← 0.5  features/cones.feature:29:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape.closed ← true  features/cones.feature:30:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(vector(0, 1, 1))  features/cones.feature:31:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -0.25), direction)  features/cones.feature:32:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(shape, r)  features/cones.feature:33:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/cones.feature:34:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a cone's end caps 2  features/cones.feature:36:12 [INFO] [stdout]  - Given shape ← cone()  features/cones.feature:27:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape.minimum ← -0.5  features/cones.feature:28:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape.maximum ← 0.5  features/cones.feature:29:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape.closed ← true  features/cones.feature:30:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(vector(0, 1, 0))  features/cones.feature:31:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -0.25), direction)  features/cones.feature:32:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(shape, r)  features/cones.feature:33:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 4  features/cones.feature:34:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Computing the normal vector on a cone 0 features/cones.feature:47:12 [INFO] [stdout]  - Given shape ← cone()  features/cones.feature:43:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← local_normal_at(shape, point(0, 0, 0)) features/cones.feature:44:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(0, 0, 0)  features/cones.feature:45:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Computing the normal vector on a cone 1 features/cones.feature:47:12 [INFO] [stdout]  - Given shape ← cone()  features/cones.feature:43:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← local_normal_at(shape, point(1, 1, 1)) features/cones.feature:44:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(1, -√2, 1)  features/cones.feature:45:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Computing the normal vector on a cone 2 features/cones.feature:47:12 [INFO] [stdout]  - Given shape ← cone()  features/cones.feature:43:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← local_normal_at(shape, point(-1, -1, 0)) [INFO] [stdout]  features/cones.feature:44:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(-1, 1, 0)  features/cones.feature:45:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: Constructive Solid Geometry (CSG)  features/csg.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: CSG is created with an operation and two shapes [INFO] [stdout]  features/csg.feature:3:11 [INFO] [stdout]  - Given s1 ← sphere()  features/csg.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s2 ← cube()  features/csg.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When c ← csg("union", s1, s2)  features/csg.feature:6:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c.operation = "union"  features/csg.feature:7:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c.left = s1  features/csg.feature:8:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c.right = s2  features/csg.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s1.parent = c  features/csg.feature:10:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s2.parent = c  features/csg.feature:11:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 0 features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("union", true, true, true) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = false  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 1 features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("union", true, true, false) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = true  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 2 features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("union", true, false, true) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = false  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 3 features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("union", true, false, false) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = true  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 4 features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("union", false, true, true) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = false  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 5 features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("union", false, true, false) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = false  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 6 features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("union", false, false, true) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = true  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 7 features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("union", false, false, false) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = true  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 8 features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("intersection", true, true, true) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = true  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 9 features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("intersection", true, true, false) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = false  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 10 [INFO] [stdout]  features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("intersection", true, false, true) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = true  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 11 [INFO] [stdout]  features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("intersection", true, false, false) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = false  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 12 [INFO] [stdout]  features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("intersection", false, true, true) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = true  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 13 [INFO] [stdout]  features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("intersection", false, true, false) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = true  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 14 [INFO] [stdout]  features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("intersection", false, false, true) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = false  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 15 [INFO] [stdout]  features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("intersection", false, false, false) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = false  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 16 [INFO] [stdout]  features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("difference", true, true, true) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = false  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 17 [INFO] [stdout]  features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("difference", true, true, false) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = true  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 18 [INFO] [stdout]  features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("difference", true, false, true) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = false  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 19 [INFO] [stdout]  features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("difference", true, false, false) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = true  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 20 [INFO] [stdout]  features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("difference", false, true, true) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = true  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 21 [INFO] [stdout]  features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("difference", false, true, false) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = true  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 22 [INFO] [stdout]  features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("difference", false, false, true) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = false  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Evaluating the rule for a CSG operation 23 [INFO] [stdout]  features/csg.feature:17:12 [INFO] [stdout]  - When result ← intersection_allowed("difference", false, false, false) [INFO] [stdout]  features/csg.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = false  features/csg.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Filtering a list of intersections 0  features/csg.feature:56:12 [INFO] [stdout]  - Given s1 ← sphere()  features/csg.feature:47:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s2 ← cube()  features/csg.feature:48:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c ← csg("union", s1, s2)  features/csg.feature:49:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(1:s1, 2:s2, 3:s1, 4:s2)  features/csg.feature:50:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When result ← filter_intersections(c, xs)  features/csg.feature:51:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result.count = 2  features/csg.feature:52:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And result[0] = xs[0]  features/csg.feature:53:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And result[1] = xs[3]  features/csg.feature:54:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Filtering a list of intersections 1  features/csg.feature:56:12 [INFO] [stdout]  - Given s1 ← sphere()  features/csg.feature:47:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s2 ← cube()  features/csg.feature:48:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c ← csg("intersection", s1, s2)  features/csg.feature:49:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(1:s1, 2:s2, 3:s1, 4:s2)  features/csg.feature:50:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When result ← filter_intersections(c, xs)  features/csg.feature:51:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result.count = 2  features/csg.feature:52:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And result[0] = xs[1]  features/csg.feature:53:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And result[1] = xs[2]  features/csg.feature:54:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Filtering a list of intersections 2  features/csg.feature:56:12 [INFO] [stdout]  - Given s1 ← sphere()  features/csg.feature:47:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s2 ← cube()  features/csg.feature:48:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c ← csg("difference", s1, s2)  features/csg.feature:49:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(1:s1, 2:s2, 3:s1, 4:s2)  features/csg.feature:50:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When result ← filter_intersections(c, xs)  features/csg.feature:51:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result.count = 2  features/csg.feature:52:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And result[0] = xs[0]  features/csg.feature:53:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And result[1] = xs[1]  features/csg.feature:54:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray misses a CSG object  features/csg.feature:62:11 [INFO] [stdout]  - Given c ← csg("union", sphere(), cube())  features/csg.feature:63:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 2, -5), vector(0, 0, 1))  features/csg.feature:64:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(c, r)  features/csg.feature:65:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs is empty  features/csg.feature:66:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray hits a CSG object  features/csg.feature:68:11 [INFO] [stdout]  - Given s1 ← sphere()  features/csg.feature:69:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s2 ← sphere()  features/csg.feature:70:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(s2, translation(0, 0, 0.5))  features/csg.feature:71:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c ← csg("union", s1, s2)  features/csg.feature:72:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -5), vector(0, 0, 1))  features/csg.feature:73:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(c, r)  features/csg.feature:74:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/csg.feature:75:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = 4  features/csg.feature:76:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].object = s1  features/csg.feature:77:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].t = 6.5  features/csg.feature:78:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].object = s2  features/csg.feature:79:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: Cubes  features/cubes.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: A ray intersects a cube 0  features/cubes.feature:11:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(+x, point(5, 0.5, 0))  features/cubes.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(c, r)  features/cubes.feature:6:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/cubes.feature:7:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = vector(-1, 0, 0)  features/cubes.feature:8:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].t = 4  features/cubes.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray intersects a cube 1  features/cubes.feature:11:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(-x, point(-5, 0.5, 0))  features/cubes.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(c, r)  features/cubes.feature:6:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/cubes.feature:7:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = vector(1, 0, 0)  features/cubes.feature:8:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].t = 4  features/cubes.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray intersects a cube 2  features/cubes.feature:11:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(+y, point(0.5, 5, 0))  features/cubes.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(c, r)  features/cubes.feature:6:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/cubes.feature:7:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = vector(0, -1, 0)  features/cubes.feature:8:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].t = 4  features/cubes.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray intersects a cube 3  features/cubes.feature:11:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(-y, point(0.5, -5, 0))  features/cubes.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(c, r)  features/cubes.feature:6:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/cubes.feature:7:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = vector(0, 1, 0)  features/cubes.feature:8:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].t = 4  features/cubes.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray intersects a cube 4  features/cubes.feature:11:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(+z, point(0.5, 0, 5))  features/cubes.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(c, r)  features/cubes.feature:6:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/cubes.feature:7:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = vector(0, 0, -1)  features/cubes.feature:8:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].t = 4  features/cubes.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray intersects a cube 5  features/cubes.feature:11:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(-z, point(0.5, 0, -5))  features/cubes.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(c, r)  features/cubes.feature:6:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/cubes.feature:7:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = vector(0, 0, 1)  features/cubes.feature:8:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].t = 4  features/cubes.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray intersects a cube 6  features/cubes.feature:11:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(inside, point(0, 0.5, 0))  features/cubes.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(c, r)  features/cubes.feature:6:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/cubes.feature:7:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = vector(0, 0, 1)  features/cubes.feature:8:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].t = -1  features/cubes.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray misses a cube 0  features/cubes.feature:27:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:22:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(-2, 0, 0), vector(0.2673, 0.5345, 0.8018)) [INFO] [stdout]  features/cubes.feature:23:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(c, r)  features/cubes.feature:24:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 0  features/cubes.feature:25:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray misses a cube 1  features/cubes.feature:27:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:22:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, -2, 0), vector(0.8018, 0.2673, 0.5345)) [INFO] [stdout]  features/cubes.feature:23:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(c, r)  features/cubes.feature:24:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 0  features/cubes.feature:25:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray misses a cube 2  features/cubes.feature:27:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:22:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -2), vector(0.5345, 0.8018, 0.2673)) [INFO] [stdout]  features/cubes.feature:23:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(c, r)  features/cubes.feature:24:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 0  features/cubes.feature:25:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray misses a cube 3  features/cubes.feature:27:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:22:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(2, 0, 2), vector(0, 0, -1))  features/cubes.feature:23:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(c, r)  features/cubes.feature:24:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 0  features/cubes.feature:25:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray misses a cube 4  features/cubes.feature:27:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:22:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 2, 2), vector(0, -1, 0))  features/cubes.feature:23:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(c, r)  features/cubes.feature:24:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 0  features/cubes.feature:25:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray misses a cube 5  features/cubes.feature:27:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:22:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(2, 2, 0), vector(-1, 0, 0))  features/cubes.feature:23:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(c, r)  features/cubes.feature:24:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 0  features/cubes.feature:25:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The normal on the surface of a cube 0  features/cubes.feature:43:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:38:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(1, 0.5, -0.8)  features/cubes.feature:39:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When normal ← local_normal_at(c, p)  features/cubes.feature:40:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then normal = vector(1, 0, 0)  features/cubes.feature:41:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The normal on the surface of a cube 1  features/cubes.feature:43:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:38:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(-1, -0.2, 0.9)  features/cubes.feature:39:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When normal ← local_normal_at(c, p)  features/cubes.feature:40:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then normal = vector(-1, 0, 0)  features/cubes.feature:41:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The normal on the surface of a cube 2  features/cubes.feature:43:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:38:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(-0.4, 1, -0.1)  features/cubes.feature:39:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When normal ← local_normal_at(c, p)  features/cubes.feature:40:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then normal = vector(0, 1, 0)  features/cubes.feature:41:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The normal on the surface of a cube 3  features/cubes.feature:43:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:38:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(0.3, -1, -0.7)  features/cubes.feature:39:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When normal ← local_normal_at(c, p)  features/cubes.feature:40:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then normal = vector(0, -1, 0)  features/cubes.feature:41:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The normal on the surface of a cube 4  features/cubes.feature:43:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:38:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(-0.6, 0.3, 1)  features/cubes.feature:39:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When normal ← local_normal_at(c, p)  features/cubes.feature:40:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then normal = vector(0, 0, 1)  features/cubes.feature:41:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The normal on the surface of a cube 5  features/cubes.feature:43:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:38:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(0.4, 0.4, -1)  features/cubes.feature:39:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When normal ← local_normal_at(c, p)  features/cubes.feature:40:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then normal = vector(0, 0, -1)  features/cubes.feature:41:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The normal on the surface of a cube 6  features/cubes.feature:43:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:38:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(1, 1, 1)  features/cubes.feature:39:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When normal ← local_normal_at(c, p)  features/cubes.feature:40:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then normal = vector(1, 0, 0)  features/cubes.feature:41:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The normal on the surface of a cube 7  features/cubes.feature:43:12 [INFO] [stdout]  - Given c ← cube()  features/cubes.feature:38:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(-1, -1, -1)  features/cubes.feature:39:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When normal ← local_normal_at(c, p)  features/cubes.feature:40:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then normal = vector(-1, 0, 0)  features/cubes.feature:41:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: Cylinders  features/cylinders.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: A ray misses a cylinder 0  features/cylinders.feature:10:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(vector(0, 1, 0))  features/cylinders.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(1, 0, 0), direction)  features/cylinders.feature:6:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(cyl, r)  features/cylinders.feature:7:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 0  features/cylinders.feature:8:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray misses a cylinder 1  features/cylinders.feature:10:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(vector(0, 1, 0))  features/cylinders.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, 0), direction)  features/cylinders.feature:6:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(cyl, r)  features/cylinders.feature:7:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 0  features/cylinders.feature:8:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray misses a cylinder 2  features/cylinders.feature:10:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(vector(1, 1, 1))  features/cylinders.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -5), direction)  features/cylinders.feature:6:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(cyl, r)  features/cylinders.feature:7:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 0  features/cylinders.feature:8:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray strikes a cylinder 0  features/cylinders.feature:25:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:17:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(vector(0, 0, 1))  features/cylinders.feature:18:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(1, 0, -5), direction)  features/cylinders.feature:19:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(cyl, r)  features/cylinders.feature:20:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/cylinders.feature:21:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = 5  features/cylinders.feature:22:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].t = 5  features/cylinders.feature:23:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray strikes a cylinder 1  features/cylinders.feature:25:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:17:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(vector(0, 0, 1))  features/cylinders.feature:18:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -5), direction)  features/cylinders.feature:19:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(cyl, r)  features/cylinders.feature:20:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/cylinders.feature:21:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = 4  features/cylinders.feature:22:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].t = 6  features/cylinders.feature:23:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray strikes a cylinder 2  features/cylinders.feature:25:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:17:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(vector(0.1, 1, 1)) [INFO] [stdout]  features/cylinders.feature:18:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0.5, 0, -5), direction)  features/cylinders.feature:19:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(cyl, r)  features/cylinders.feature:20:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/cylinders.feature:21:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = 6.80798  features/cylinders.feature:22:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].t = 7.08872  features/cylinders.feature:23:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Normal vector on a cylinder 0  features/cylinders.feature:36:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:32:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← local_normal_at(cyl, point(1, 0, 0)) [INFO] [stdout]  features/cylinders.feature:33:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(1, 0, 0)  features/cylinders.feature:34:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Normal vector on a cylinder 1  features/cylinders.feature:36:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:32:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← local_normal_at(cyl, point(0, 5, -1)) [INFO] [stdout]  features/cylinders.feature:33:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(0, 0, -1)  features/cylinders.feature:34:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Normal vector on a cylinder 2  features/cylinders.feature:36:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:32:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← local_normal_at(cyl, point(0, -2, 1)) [INFO] [stdout]  features/cylinders.feature:33:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(0, 0, 1)  features/cylinders.feature:34:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Normal vector on a cylinder 3  features/cylinders.feature:36:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:32:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← local_normal_at(cyl, point(-1, 1, 0)) [INFO] [stdout]  features/cylinders.feature:33:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(-1, 0, 0)  features/cylinders.feature:34:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The default minimum and maximum for a cylinder [INFO] [stdout]  features/cylinders.feature:43:11 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:44:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then cyl.minimum = -infinity  features/cylinders.feature:45:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.maximum = infinity  features/cylinders.feature:46:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a constrained cylinder 0 [INFO] [stdout]  features/cylinders.feature:57:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:49:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.minimum ← 1  features/cylinders.feature:50:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.maximum ← 2  features/cylinders.feature:51:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(point(0, 1.5, 0)) features/cylinders.feature:52:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(1, direction)  features/cylinders.feature:53:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(cyl, r)  features/cylinders.feature:54:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = vector(0.1, 1, 0)  features/cylinders.feature:55:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a constrained cylinder 1 [INFO] [stdout]  features/cylinders.feature:57:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:49:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.minimum ← 1  features/cylinders.feature:50:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.maximum ← 2  features/cylinders.feature:51:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(point(0, 3, -5))  features/cylinders.feature:52:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(2, direction)  features/cylinders.feature:53:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(cyl, r)  features/cylinders.feature:54:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = vector(0, 0, 1)  features/cylinders.feature:55:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a constrained cylinder 2 [INFO] [stdout]  features/cylinders.feature:57:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:49:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.minimum ← 1  features/cylinders.feature:50:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.maximum ← 2  features/cylinders.feature:51:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(point(0, 0, -5))  features/cylinders.feature:52:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(3, direction)  features/cylinders.feature:53:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(cyl, r)  features/cylinders.feature:54:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = vector(0, 0, 1)  features/cylinders.feature:55:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a constrained cylinder 3 [INFO] [stdout]  features/cylinders.feature:57:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:49:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.minimum ← 1  features/cylinders.feature:50:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.maximum ← 2  features/cylinders.feature:51:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(point(0, 2, -5))  features/cylinders.feature:52:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(4, direction)  features/cylinders.feature:53:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(cyl, r)  features/cylinders.feature:54:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = vector(0, 0, 1)  features/cylinders.feature:55:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a constrained cylinder 4 [INFO] [stdout]  features/cylinders.feature:57:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:49:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.minimum ← 1  features/cylinders.feature:50:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.maximum ← 2  features/cylinders.feature:51:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(point(0, 1, -5))  features/cylinders.feature:52:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(5, direction)  features/cylinders.feature:53:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(cyl, r)  features/cylinders.feature:54:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = vector(0, 0, 1)  features/cylinders.feature:55:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a constrained cylinder 5 [INFO] [stdout]  features/cylinders.feature:57:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:49:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.minimum ← 1  features/cylinders.feature:50:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.maximum ← 2  features/cylinders.feature:51:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(point(0, 1.5, -2)) [INFO] [stdout]  features/cylinders.feature:52:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(6, direction)  features/cylinders.feature:53:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(cyl, r)  features/cylinders.feature:54:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = vector(0, 0, 1)  features/cylinders.feature:55:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The default closed value for a cylinder [INFO] [stdout]  features/cylinders.feature:66:11 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:67:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then cyl.closed = false  features/cylinders.feature:68:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting the caps of a closed cylinder 0 [INFO] [stdout]  features/cylinders.feature:80:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:71:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.minimum ← 1  features/cylinders.feature:72:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.maximum ← 2  features/cylinders.feature:73:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.closed ← true  features/cylinders.feature:74:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(point(0, 3, 0))  features/cylinders.feature:75:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(1, direction)  features/cylinders.feature:76:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(cyl, r)  features/cylinders.feature:77:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = vector(0, -1, 0)  features/cylinders.feature:78:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting the caps of a closed cylinder 1 [INFO] [stdout]  features/cylinders.feature:80:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:71:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.minimum ← 1  features/cylinders.feature:72:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.maximum ← 2  features/cylinders.feature:73:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.closed ← true  features/cylinders.feature:74:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(point(0, 3, -2))  features/cylinders.feature:75:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(2, direction)  features/cylinders.feature:76:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(cyl, r)  features/cylinders.feature:77:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = vector(0, -1, 2)  features/cylinders.feature:78:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting the caps of a closed cylinder 2 [INFO] [stdout]  features/cylinders.feature:80:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:71:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.minimum ← 1  features/cylinders.feature:72:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.maximum ← 2  features/cylinders.feature:73:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.closed ← true  features/cylinders.feature:74:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(point(0, 4, -2))  features/cylinders.feature:75:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(3, direction)  features/cylinders.feature:76:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(cyl, r)  features/cylinders.feature:77:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = vector(0, -1, 1)  features/cylinders.feature:78:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting the caps of a closed cylinder 3 [INFO] [stdout]  features/cylinders.feature:80:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:71:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.minimum ← 1  features/cylinders.feature:72:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.maximum ← 2  features/cylinders.feature:73:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.closed ← true  features/cylinders.feature:74:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← normalize(point(0, -1, -2)) features/cylinders.feature:75:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(5, direction)  features/cylinders.feature:76:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(cyl, r)  features/cylinders.feature:77:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = vector(0, 1, 1)  features/cylinders.feature:78:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The normal vector on a cylinder's end caps 0 [INFO] [stdout]  features/cylinders.feature:96:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:89:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.minimum ← 1  features/cylinders.feature:90:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.maximum ← 2  features/cylinders.feature:91:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.closed ← true  features/cylinders.feature:92:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← local_normal_at(cyl, point(0, 1, 0)) [INFO] [stdout]  features/cylinders.feature:93:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(0, -1, 0)  features/cylinders.feature:94:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The normal vector on a cylinder's end caps 1 [INFO] [stdout]  features/cylinders.feature:96:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:89:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.minimum ← 1  features/cylinders.feature:90:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.maximum ← 2  features/cylinders.feature:91:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.closed ← true  features/cylinders.feature:92:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← local_normal_at(cyl, point(0.5, 1, 0)) [INFO] [stdout]  features/cylinders.feature:93:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(0, -1, 0)  features/cylinders.feature:94:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The normal vector on a cylinder's end caps 2 [INFO] [stdout]  features/cylinders.feature:96:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:89:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.minimum ← 1  features/cylinders.feature:90:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.maximum ← 2  features/cylinders.feature:91:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.closed ← true  features/cylinders.feature:92:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← local_normal_at(cyl, point(0, 1, 0.5)) [INFO] [stdout]  features/cylinders.feature:93:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(0, -1, 0)  features/cylinders.feature:94:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The normal vector on a cylinder's end caps 3 [INFO] [stdout]  features/cylinders.feature:96:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:89:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.minimum ← 1  features/cylinders.feature:90:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.maximum ← 2  features/cylinders.feature:91:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.closed ← true  features/cylinders.feature:92:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← local_normal_at(cyl, point(0, 2, 0)) [INFO] [stdout]  features/cylinders.feature:93:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(0, 1, 0)  features/cylinders.feature:94:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The normal vector on a cylinder's end caps 4 [INFO] [stdout]  features/cylinders.feature:96:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:89:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.minimum ← 1  features/cylinders.feature:90:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.maximum ← 2  features/cylinders.feature:91:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.closed ← true  features/cylinders.feature:92:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← local_normal_at(cyl, point(0.5, 2, 0)) [INFO] [stdout]  features/cylinders.feature:93:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(0, 1, 0)  features/cylinders.feature:94:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The normal vector on a cylinder's end caps 5 [INFO] [stdout]  features/cylinders.feature:96:12 [INFO] [stdout]  - Given cyl ← cylinder()  features/cylinders.feature:89:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.minimum ← 1  features/cylinders.feature:90:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.maximum ← 2  features/cylinders.feature:91:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cyl.closed ← true  features/cylinders.feature:92:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← local_normal_at(cyl, point(0, 2, 0.5)) [INFO] [stdout]  features/cylinders.feature:93:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(0, 1, 0)  features/cylinders.feature:94:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: Groups  features/groups.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: Creating a new group  features/groups.feature:3:11 [INFO] [stdout]  - Given g ← group()  features/groups.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then g.transform = identity_matrix  features/groups.feature:5:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And g is empty  features/groups.feature:6:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Adding a child to a group  features/groups.feature:8:11 [INFO] [stdout]  - Given g ← group()  features/groups.feature:9:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s ← test_shape()  features/groups.feature:10:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When add_child(g, s)  features/groups.feature:11:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then g is not empty  features/groups.feature:12:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And g includes s  features/groups.feature:13:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s.parent = g  features/groups.feature:14:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a ray with an empty group features/groups.feature:16:11 [INFO] [stdout]  - Given g ← group()  features/groups.feature:17:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, 0), vector(0, 0, 1))  features/groups.feature:18:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(g, r)  features/groups.feature:19:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs is empty  features/groups.feature:20:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a ray with a nonempty group [INFO] [stdout]  features/groups.feature:22:11 [INFO] [stdout]  - Given g ← group()  features/groups.feature:23:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s1 ← sphere()  features/groups.feature:24:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s2 ← sphere()  features/groups.feature:25:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(s2, translation(0, 0, -3))  features/groups.feature:26:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s3 ← sphere()  features/groups.feature:27:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(s3, translation(5, 0, 0))  features/groups.feature:28:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And add_child(g, s1)  features/groups.feature:29:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And add_child(g, s2)  features/groups.feature:30:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And add_child(g, s3)  features/groups.feature:31:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When r ← ray(point(0, 0, -5), vector(0, 0, 1)) features/groups.feature:32:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← local_intersect(g, r)  features/groups.feature:33:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 4  features/groups.feature:34:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].object = s2  features/groups.feature:35:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].object = s2  features/groups.feature:36:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[2].object = s1  features/groups.feature:37:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[3].object = s1  features/groups.feature:38:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a transformed group  features/groups.feature:40:11 [INFO] [stdout]  - Given g ← group()  features/groups.feature:41:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(g, scaling(2, 2, 2))  features/groups.feature:42:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s ← sphere()  features/groups.feature:43:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(s, translation(5, 0, 0))  features/groups.feature:44:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And add_child(g, s)  features/groups.feature:45:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When r ← ray(point(10, 0, -10), vector(0, 0, 1)) [INFO] [stdout]  features/groups.feature:46:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersect(g, r)  features/groups.feature:47:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/groups.feature:48:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: Intersections  features/intersections.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: An intersection encapsulates t and object [INFO] [stdout]  features/intersections.feature:3:11 [INFO] [stdout]  - Given s ← sphere()  features/intersections.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When i ← intersection(3.5, s)  features/intersections.feature:5:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then i.t = 3.5  features/intersections.feature:6:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i.object = s  features/intersections.feature:7:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Precomputing the state of an intersection [INFO] [stdout]  features/intersections.feature:9:11 [INFO] [stdout]  - Given r ← ray(point(0, 0, -5), vector(0, 0, 1)) [INFO] [stdout]  features/intersections.feature:10:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape ← sphere()  features/intersections.feature:11:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i ← intersection(4, shape)  features/intersections.feature:12:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(i, r) features/intersections.feature:13:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then comps.t = i.t  features/intersections.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And comps.object = i.object  features/intersections.feature:15:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And comps.point = point(0, 0, -1)  features/intersections.feature:16:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And comps.eyev = vector(0, 0, -1)  features/intersections.feature:17:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And comps.normalv = vector(0, 0, -1)  features/intersections.feature:18:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Precomputing the reflection vector [INFO] [stdout]  features/intersections.feature:20:11 [INFO] [stdout]  - Given shape ← plane()  features/intersections.feature:21:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 1, -1), vector(0, -√2/2, √2/2)) [INFO] [stdout]  features/intersections.feature:22:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i ← intersection(√2, shape)  features/intersections.feature:23:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(i, r) features/intersections.feature:24:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then comps.reflectv = vector(0, √2/2, √2/2) [INFO] [stdout]  features/intersections.feature:25:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The hit, when an intersection occurs on the outside [INFO] [stdout]  features/intersections.feature:27:11 [INFO] [stdout]  - Given r ← ray(point(0, 0, -5), vector(0, 0, 1)) [INFO] [stdout]  features/intersections.feature:28:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape ← sphere()  features/intersections.feature:29:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i ← intersection(4, shape)  features/intersections.feature:30:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(i, r) features/intersections.feature:31:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then comps.inside = false  features/intersections.feature:32:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The hit, when an intersection occurs on the inside [INFO] [stdout]  features/intersections.feature:34:11 [INFO] [stdout]  - Given r ← ray(point(0, 0, 0), vector(0, 0, 1)) [INFO] [stdout]  features/intersections.feature:35:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape ← sphere()  features/intersections.feature:36:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i ← intersection(1, shape)  features/intersections.feature:37:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(i, r) features/intersections.feature:38:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then comps.point = point(0, 0, 1)  features/intersections.feature:39:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And comps.eyev = vector(0, 0, -1)  features/intersections.feature:40:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And comps.inside = true  features/intersections.feature:41:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And comps.normalv = vector(0, 0, -1)  features/intersections.feature:43:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The hit should offset the point features/intersections.feature:45:11 [INFO] [stdout]  - Given r ← ray(point(0, 0, -5), vector(0, 0, 1)) [INFO] [stdout]  features/intersections.feature:46:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape ← sphere() with:  features/intersections.feature:47:5 [INFO] [stdout]  | | | [INFO] [stdout] | transform | translation(0, 0, 1) | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i ← intersection(5, shape)  features/intersections.feature:49:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(i, r) features/intersections.feature:50:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then comps.over_point.z < -EPSILON/2  features/intersections.feature:51:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And comps.point.z > comps.over_point.z  features/intersections.feature:52:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The under point is offset below the surface [INFO] [stdout]  features/intersections.feature:54:11 [INFO] [stdout]  - Given r ← ray(point(0, 0, -5), vector(0, 0, 1)) [INFO] [stdout]  features/intersections.feature:55:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape ← glass_sphere() with:  features/intersections.feature:56:5 [INFO] [stdout]  | | | [INFO] [stdout] | transform | translation(0, 0, 1) | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i ← intersection(5, shape)  features/intersections.feature:58:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(i)  features/intersections.feature:59:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(i, r, xs) [INFO] [stdout]  features/intersections.feature:60:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then comps.under_point.z > EPSILON/2  features/intersections.feature:61:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And comps.point.z < comps.under_point.z features/intersections.feature:62:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Aggregating intersections  features/intersections.feature:64:11 [INFO] [stdout]  - Given s ← sphere()  features/intersections.feature:65:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i1 ← intersection(1, s)  features/intersections.feature:66:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i2 ← intersection(2, s)  features/intersections.feature:67:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← intersections(i1, i2)  features/intersections.feature:68:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/intersections.feature:69:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = 1  features/intersections.feature:70:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].t = 2  features/intersections.feature:71:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The hit, when all intersections have positive t [INFO] [stdout]  features/intersections.feature:73:11 [INFO] [stdout]  - Given s ← sphere()  features/intersections.feature:74:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i1 ← intersection(1, s)  features/intersections.feature:75:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i2 ← intersection(2, s)  features/intersections.feature:76:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(i2, i1)  features/intersections.feature:77:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When i ← hit(xs)  features/intersections.feature:78:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then i = i1  features/intersections.feature:79:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The hit, when some intersections have negative t [INFO] [stdout]  features/intersections.feature:81:11 [INFO] [stdout]  - Given s ← sphere()  features/intersections.feature:82:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i1 ← intersection(-1, s)  features/intersections.feature:83:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i2 ← intersection(1, s)  features/intersections.feature:84:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(i2, i1)  features/intersections.feature:85:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When i ← hit(xs)  features/intersections.feature:86:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then i = i2  features/intersections.feature:87:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The hit, when all intersections have negative t [INFO] [stdout]  features/intersections.feature:89:11 [INFO] [stdout]  - Given s ← sphere()  features/intersections.feature:90:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i1 ← intersection(-2, s)  features/intersections.feature:91:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i2 ← intersection(-1, s)  features/intersections.feature:92:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(i2, i1)  features/intersections.feature:93:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When i ← hit(xs)  features/intersections.feature:94:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then i is nothing  features/intersections.feature:95:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The hit is always the lowest nonnegative intersection [INFO] [stdout]  features/intersections.feature:97:11 [INFO] [stdout]  - Given s ← sphere()  features/intersections.feature:98:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i1 ← intersection(5, s)  features/intersections.feature:99:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i2 ← intersection(7, s)  features/intersections.feature:100:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i3 ← intersection(-3, s)  features/intersections.feature:101:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i4 ← intersection(2, s)  features/intersections.feature:102:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(i1, i2, i3, i4) features/intersections.feature:103:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When i ← hit(xs)  features/intersections.feature:104:1 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then i = i4  features/intersections.feature:105:1 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Finding n1 and n2 at various intersections 0 [INFO] [stdout]  features/intersections.feature:123:12 [INFO] [stdout]  - Given A ← glass_sphere() with:  features/intersections.feature:108:3 [INFO] [stdout]  | transform | scaling(2, 2, 2) | [INFO] [stdout] | material.refractive_index | 1.5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And B ← glass_sphere() with:  features/intersections.feature:111:5 [INFO] [stdout]  | transform | translation(0, 0, -0.25) | [INFO] [stdout] | material.refractive_index | 2.0 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And C ← glass_sphere() with:  features/intersections.feature:114:5 [INFO] [stdout]  | transform | translation(0, 0, 0.25) | [INFO] [stdout] | material.refractive_index | 2.5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -4), vector(0, 0, 1)) [INFO] [stdout]  features/intersections.feature:117:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(2:A, 2.75:B, 3.25:C, 4.75:B, 5.25:C, 6:A) [INFO] [stdout]  features/intersections.feature:118:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(xs[0], r, xs) [INFO] [stdout]  features/intersections.feature:119:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then comps.n1 = 1.0  features/intersections.feature:120:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And comps.n2 = 1.5  features/intersections.feature:121:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Finding n1 and n2 at various intersections 1 [INFO] [stdout]  features/intersections.feature:123:12 [INFO] [stdout]  - Given A ← glass_sphere() with:  features/intersections.feature:108:3 [INFO] [stdout]  | transform | scaling(2, 2, 2) | [INFO] [stdout] | material.refractive_index | 1.5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And B ← glass_sphere() with:  features/intersections.feature:111:5 [INFO] [stdout]  | transform | translation(0, 0, -0.25) | [INFO] [stdout] | material.refractive_index | 2.0 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And C ← glass_sphere() with:  features/intersections.feature:114:5 [INFO] [stdout]  | transform | translation(0, 0, 0.25) | [INFO] [stdout] | material.refractive_index | 2.5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -4), vector(0, 0, 1)) [INFO] [stdout]  features/intersections.feature:117:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(2:A, 2.75:B, 3.25:C, 4.75:B, 5.25:C, 6:A) [INFO] [stdout]  features/intersections.feature:118:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(xs[1], r, xs) [INFO] [stdout]  features/intersections.feature:119:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then comps.n1 = 1.5  features/intersections.feature:120:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And comps.n2 = 2.0  features/intersections.feature:121:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Finding n1 and n2 at various intersections 2 [INFO] [stdout]  features/intersections.feature:123:12 [INFO] [stdout]  - Given A ← glass_sphere() with:  features/intersections.feature:108:3 [INFO] [stdout]  | transform | scaling(2, 2, 2) | [INFO] [stdout] | material.refractive_index | 1.5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And B ← glass_sphere() with:  features/intersections.feature:111:5 [INFO] [stdout]  | transform | translation(0, 0, -0.25) | [INFO] [stdout] | material.refractive_index | 2.0 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And C ← glass_sphere() with:  features/intersections.feature:114:5 [INFO] [stdout]  | transform | translation(0, 0, 0.25) | [INFO] [stdout] | material.refractive_index | 2.5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -4), vector(0, 0, 1)) [INFO] [stdout]  features/intersections.feature:117:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(2:A, 2.75:B, 3.25:C, 4.75:B, 5.25:C, 6:A) [INFO] [stdout]  features/intersections.feature:118:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(xs[2], r, xs) [INFO] [stdout]  features/intersections.feature:119:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then comps.n1 = 2.0  features/intersections.feature:120:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And comps.n2 = 2.5  features/intersections.feature:121:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Finding n1 and n2 at various intersections 3 [INFO] [stdout]  features/intersections.feature:123:12 [INFO] [stdout]  - Given A ← glass_sphere() with:  features/intersections.feature:108:3 [INFO] [stdout]  | transform | scaling(2, 2, 2) | [INFO] [stdout] | material.refractive_index | 1.5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And B ← glass_sphere() with:  features/intersections.feature:111:5 [INFO] [stdout]  | transform | translation(0, 0, -0.25) | [INFO] [stdout] | material.refractive_index | 2.0 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And C ← glass_sphere() with:  features/intersections.feature:114:5 [INFO] [stdout]  | transform | translation(0, 0, 0.25) | [INFO] [stdout] | material.refractive_index | 2.5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -4), vector(0, 0, 1)) [INFO] [stdout]  features/intersections.feature:117:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(2:A, 2.75:B, 3.25:C, 4.75:B, 5.25:C, 6:A) [INFO] [stdout]  features/intersections.feature:118:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(xs[3], r, xs) [INFO] [stdout]  features/intersections.feature:119:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then comps.n1 = 2.5  features/intersections.feature:120:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And comps.n2 = 2.5  features/intersections.feature:121:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Finding n1 and n2 at various intersections 4 [INFO] [stdout]  features/intersections.feature:123:12 [INFO] [stdout]  - Given A ← glass_sphere() with:  features/intersections.feature:108:3 [INFO] [stdout]  | transform | scaling(2, 2, 2) | [INFO] [stdout] | material.refractive_index | 1.5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And B ← glass_sphere() with:  features/intersections.feature:111:5 [INFO] [stdout]  | transform | translation(0, 0, -0.25) | [INFO] [stdout] | material.refractive_index | 2.0 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And C ← glass_sphere() with:  features/intersections.feature:114:5 [INFO] [stdout]  | transform | translation(0, 0, 0.25) | [INFO] [stdout] | material.refractive_index | 2.5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -4), vector(0, 0, 1)) [INFO] [stdout]  features/intersections.feature:117:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(2:A, 2.75:B, 3.25:C, 4.75:B, 5.25:C, 6:A) [INFO] [stdout]  features/intersections.feature:118:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(xs[4], r, xs) [INFO] [stdout]  features/intersections.feature:119:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then comps.n1 = 2.5  features/intersections.feature:120:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And comps.n2 = 1.5  features/intersections.feature:121:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Finding n1 and n2 at various intersections 5 [INFO] [stdout]  features/intersections.feature:123:12 [INFO] [stdout]  - Given A ← glass_sphere() with:  features/intersections.feature:108:3 [INFO] [stdout]  | transform | scaling(2, 2, 2) | [INFO] [stdout] | material.refractive_index | 1.5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And B ← glass_sphere() with:  features/intersections.feature:111:5 [INFO] [stdout]  | transform | translation(0, 0, -0.25) | [INFO] [stdout] | material.refractive_index | 2.0 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And C ← glass_sphere() with:  features/intersections.feature:114:5 [INFO] [stdout]  | transform | translation(0, 0, 0.25) | [INFO] [stdout] | material.refractive_index | 2.5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -4), vector(0, 0, 1)) [INFO] [stdout]  features/intersections.feature:117:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(2:A, 2.75:B, 3.25:C, 4.75:B, 5.25:C, 6:A) [INFO] [stdout]  features/intersections.feature:118:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(xs[5], r, xs) [INFO] [stdout]  features/intersections.feature:119:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then comps.n1 = 1.5  features/intersections.feature:120:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And comps.n2 = 1.0  features/intersections.feature:121:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The Schlick approximation under total internal reflection [INFO] [stdout]  features/intersections.feature:132:11 [INFO] [stdout]  - Given shape ← glass_sphere()  features/intersections.feature:133:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, √2/2), vector(0, 1, 0)) [INFO] [stdout]  features/intersections.feature:134:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(-√2/2:shape, √2/2:shape) [INFO] [stdout]  features/intersections.feature:135:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(xs[1], r, xs) [INFO] [stdout]  features/intersections.feature:136:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And reflectance ← schlick(comps)  features/intersections.feature:137:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then reflectance = 1.0  features/intersections.feature:138:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The Schlick approximation with a perpendicular viewing angle [INFO] [stdout]  features/intersections.feature:140:11 [INFO] [stdout]  - Given shape ← glass_sphere()  features/intersections.feature:141:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, 0), vector(0, 1, 0)) [INFO] [stdout]  features/intersections.feature:142:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(-1:shape, 1:shape) [INFO] [stdout]  features/intersections.feature:143:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(xs[1], r, xs) [INFO] [stdout]  features/intersections.feature:144:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And reflectance ← schlick(comps)  features/intersections.feature:145:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then reflectance = 0.04  features/intersections.feature:146:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The Schlick approximation with small angle and n2 > n1 [INFO] [stdout]  features/intersections.feature:148:11 [INFO] [stdout]  - Given shape ← glass_sphere()  features/intersections.feature:149:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0.99, -2), vector(0, 0, 1)) [INFO] [stdout]  features/intersections.feature:150:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(1.8589:shape)  features/intersections.feature:151:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(xs[0], r, xs) [INFO] [stdout]  features/intersections.feature:152:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And reflectance ← schlick(comps)  features/intersections.feature:153:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then reflectance = 0.48873  features/intersections.feature:154:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: An intersection can encapsulate `u` and `v` [INFO] [stdout]  features/intersections.feature:156:11 [INFO] [stdout]  - Given s ← triangle(point(0, 1, 0), point(-1, 0, 0), point(1, 0, 0)) [INFO] [stdout]  features/intersections.feature:157:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When i ← intersection_with_uv(3.5, s, 0.2, 0.4) [INFO] [stdout]  features/intersections.feature:158:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then i.u = 0.2  features/intersections.feature:159:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i.v = 0.4  features/intersections.feature:160:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: Lights  features/lights.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: A point light has a position and intensity [INFO] [stdout]  features/lights.feature:3:11 [INFO] [stdout]  - Given intensity ← color(1, 1, 1)  features/lights.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And position ← point(0, 0, 0)  features/lights.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When light ← point_light(position, intensity)  features/lights.feature:6:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then light.position = position  features/lights.feature:7:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And light.intensity = intensity  features/lights.feature:8:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: Materials  features/materials.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: The default material  features/materials.feature:7:11 [INFO] [stdout]  - Given m ← material()  features/materials.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And position ← point(0, 0, 0)  features/materials.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given m ← material()  features/materials.feature:8:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then m.color = color(1, 1, 1)  features/materials.feature:9:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And m.ambient = 0.1  features/materials.feature:10:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And m.diffuse = 0.9  features/materials.feature:11:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And m.specular = 0.9  features/materials.feature:12:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And m.shininess = 200.0  features/materials.feature:13:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Reflectivity for the default material [INFO] [stdout]  features/materials.feature:15:11 [INFO] [stdout]  - Given m ← material()  features/materials.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And position ← point(0, 0, 0)  features/materials.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given m ← material()  features/materials.feature:16:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then m.reflective = 0.0  features/materials.feature:17:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Transparency and Refractive Index for the default material [INFO] [stdout]  features/materials.feature:19:11 [INFO] [stdout]  - Given m ← material()  features/materials.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And position ← point(0, 0, 0)  features/materials.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given m ← material()  features/materials.feature:20:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then m.transparency = 0.0  features/materials.feature:21:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And m.refractive_index = 1.0  features/materials.feature:22:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Lighting with the eye between the light and the surface [INFO] [stdout]  features/materials.feature:24:11 [INFO] [stdout]  - Given m ← material()  features/materials.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And position ← point(0, 0, 0)  features/materials.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given eyev ← vector(0, 0, -1)  features/materials.feature:25:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And normalv ← vector(0, 0, -1)  features/materials.feature:26:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And light ← point_light(point(0, 0, -10), color(1, 1, 1)) [INFO] [stdout]  features/materials.feature:27:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When result ← lighting(m, light, position, eyev, normalv) [INFO] [stdout]  features/materials.feature:28:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = color(1.9, 1.9, 1.9)  features/materials.feature:29:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Lighting with the eye between light and surface, eye offset 45° [INFO] [stdout]  features/materials.feature:31:11 [INFO] [stdout]  - Given m ← material()  features/materials.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And position ← point(0, 0, 0)  features/materials.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given eyev ← vector(0, √2/2, -√2/2)  features/materials.feature:32:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And normalv ← vector(0, 0, -1)  features/materials.feature:33:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And light ← point_light(point(0, 0, -10), color(1, 1, 1)) [INFO] [stdout]  features/materials.feature:34:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When result ← lighting(m, light, position, eyev, normalv) [INFO] [stdout]  features/materials.feature:35:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = color(1.0, 1.0, 1.0)  features/materials.feature:36:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Lighting with eye opposite surface, light offset 45° [INFO] [stdout]  features/materials.feature:38:11 [INFO] [stdout]  - Given m ← material()  features/materials.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And position ← point(0, 0, 0)  features/materials.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given eyev ← vector(0, 0, -1)  features/materials.feature:39:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And normalv ← vector(0, 0, -1)  features/materials.feature:40:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And light ← point_light(point(0, 10, -10), color(1, 1, 1)) [INFO] [stdout]  features/materials.feature:41:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When result ← lighting(m, light, position, eyev, normalv) [INFO] [stdout]  features/materials.feature:42:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = color(0.7364, 0.7364, 0.7364) features/materials.feature:43:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Lighting with eye in the path of the reflection vector [INFO] [stdout]  features/materials.feature:45:11 [INFO] [stdout]  - Given m ← material()  features/materials.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And position ← point(0, 0, 0)  features/materials.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given eyev ← vector(0, -√2/2, -√2/2)  features/materials.feature:46:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And normalv ← vector(0, 0, -1)  features/materials.feature:47:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And light ← point_light(point(0, 10, -10), color(1, 1, 1)) [INFO] [stdout]  features/materials.feature:48:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When result ← lighting(m, light, position, eyev, normalv) [INFO] [stdout]  features/materials.feature:49:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = color(1.6364, 1.6364, 1.6364) features/materials.feature:50:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Lighting with the light behind the surface [INFO] [stdout]  features/materials.feature:52:11 [INFO] [stdout]  - Given m ← material()  features/materials.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And position ← point(0, 0, 0)  features/materials.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given eyev ← vector(0, 0, -1)  features/materials.feature:53:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And normalv ← vector(0, 0, -1)  features/materials.feature:54:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And light ← point_light(point(0, 0, 10), color(1, 1, 1)) [INFO] [stdout]  features/materials.feature:55:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When result ← lighting(m, light, position, eyev, normalv) [INFO] [stdout]  features/materials.feature:56:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = color(0.1, 0.1, 0.1)  features/materials.feature:57:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Lighting with the surface in shadow features/materials.feature:59:11 [INFO] [stdout]  - Given m ← material()  features/materials.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And position ← point(0, 0, 0)  features/materials.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given eyev ← vector(0, 0, -1)  features/materials.feature:60:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And normalv ← vector(0, 0, -1)  features/materials.feature:61:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And light ← point_light(point(0, 0, -10), color(1, 1, 1)) [INFO] [stdout]  features/materials.feature:62:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And in_shadow ← true  features/materials.feature:63:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When result ← lighting(m, light, position, eyev, normalv, in_shadow) [INFO] [stdout]  features/materials.feature:64:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then result = color(0.1, 0.1, 0.1)  features/materials.feature:65:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Lighting with a pattern applied  features/materials.feature:67:11 [INFO] [stdout]  - Given m ← material()  features/materials.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And position ← point(0, 0, 0)  features/materials.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given m.pattern ← stripe_pattern(color(1, 1, 1), color(0, 0, 0)) [INFO] [stdout]  features/materials.feature:68:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And m.ambient ← 1  features/materials.feature:69:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And m.diffuse ← 0  features/materials.feature:70:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And m.specular ← 0  features/materials.feature:71:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And eyev ← vector(0, 0, -1)  features/materials.feature:72:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And normalv ← vector(0, 0, -1)  features/materials.feature:73:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And light ← point_light(point(0, 0, -10), color(1, 1, 1)) [INFO] [stdout]  features/materials.feature:74:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When c1 ← lighting(m, light, point(0.9, 0, 0), eyev, normalv, false) [INFO] [stdout]  features/materials.feature:75:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c2 ← lighting(m, light, point(1.1, 0, 0), eyev, normalv, false) [INFO] [stdout]  features/materials.feature:76:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c1 = color(1, 1, 1)  features/materials.feature:77:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c2 = color(0, 0, 0)  features/materials.feature:78:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: Matrices  features/matrices.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: Constructing and inspecting a 4x4 matrix [INFO] [stdout]  features/matrices.feature:3:11 [INFO] [stdout]  - Given the following 4x4 matrix M:  features/matrices.feature:4:3 [INFO] [stdout]  | 1 | 2 | 3 | 4 | [INFO] [stdout] | 5.5 | 6.5 | 7.5 | 8.5 | [INFO] [stdout] | 9 | 10 | 11 | 12 | [INFO] [stdout] | 13.5 | 14.5 | 15.5 | 16.5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then M[0,0] = 1  features/matrices.feature:9:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And M[0,3] = 4  features/matrices.feature:10:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And M[1,0] = 5.5  features/matrices.feature:11:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And M[1,2] = 7.5  features/matrices.feature:12:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And M[2,2] = 11  features/matrices.feature:13:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And M[3,0] = 13.5  features/matrices.feature:14:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And M[3,2] = 15.5  features/matrices.feature:15:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A 2x2 matrix ought to be representable [INFO] [stdout]  features/matrices.feature:17:11 [INFO] [stdout]  - Given the following 2x2 matrix M:  features/matrices.feature:18:3 [INFO] [stdout]  | -3 | 5 | [INFO] [stdout] | 1 | -2 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then M[0,0] = -3  features/matrices.feature:21:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And M[0,1] = 5  features/matrices.feature:22:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And M[1,0] = 1  features/matrices.feature:23:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And M[1,1] = -2  features/matrices.feature:24:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A 3x3 matrix ought to be representable [INFO] [stdout]  features/matrices.feature:26:11 [INFO] [stdout]  - Given the following 3x3 matrix M:  features/matrices.feature:27:3 [INFO] [stdout]  | -3 | 5 | 0 | [INFO] [stdout] | 1 | -2 | -7 | [INFO] [stdout] | 0 | 1 | 1 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then M[0,0] = -3  features/matrices.feature:31:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And M[1,1] = -2  features/matrices.feature:32:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And M[2,2] = 1  features/matrices.feature:33:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Matrix equality with identical matrices [INFO] [stdout]  features/matrices.feature:35:11 [INFO] [stdout]  - Given the following matrix A:  features/matrices.feature:36:3 [INFO] [stdout]  | 1 | 2 | 3 | 4 | [INFO] [stdout] | 5 | 6 | 7 | 8 | [INFO] [stdout] | 9 | 8 | 7 | 6 | [INFO] [stdout] | 5 | 4 | 3 | 2 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And the following matrix B:  features/matrices.feature:41:5 [INFO] [stdout]  | 1 | 2 | 3 | 4 | [INFO] [stdout] | 5 | 6 | 7 | 8 | [INFO] [stdout] | 9 | 8 | 7 | 6 | [INFO] [stdout] | 5 | 4 | 3 | 2 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then A = B  features/matrices.feature:46:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Matrix equality with different matrices [INFO] [stdout]  features/matrices.feature:48:11 [INFO] [stdout]  - Given the following matrix A:  features/matrices.feature:49:3 [INFO] [stdout]  | 1 | 2 | 3 | 4 | [INFO] [stdout] | 5 | 6 | 7 | 8 | [INFO] [stdout] | 9 | 8 | 7 | 6 | [INFO] [stdout] | 5 | 4 | 3 | 2 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And the following matrix B:  features/matrices.feature:54:5 [INFO] [stdout]  | 2 | 3 | 4 | 5 | [INFO] [stdout] | 6 | 7 | 8 | 9 | [INFO] [stdout] | 8 | 7 | 6 | 5 | [INFO] [stdout] | 4 | 3 | 2 | 1 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then A != B  features/matrices.feature:59:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Multiplying two matrices  features/matrices.feature:61:11 [INFO] [stdout]  - Given the following matrix A:  features/matrices.feature:62:3 [INFO] [stdout]  | 1 | 2 | 3 | 4 | [INFO] [stdout] | 5 | 6 | 7 | 8 | [INFO] [stdout] | 9 | 8 | 7 | 6 | [INFO] [stdout] | 5 | 4 | 3 | 2 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And the following matrix B:  features/matrices.feature:67:5 [INFO] [stdout]  | -2 | 1 | 2 | 3 | [INFO] [stdout] | 3 | 2 | 1 | -1 | [INFO] [stdout] | 4 | 3 | 6 | 5 | [INFO] [stdout] | 1 | 2 | 7 | 8 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then A * B is the following 4x4 matrix:  features/matrices.feature:72:3 [INFO] [stdout]  | 20 | 22 | 50 | 48 | [INFO] [stdout] | 44 | 54 | 114 | 108 | [INFO] [stdout] | 40 | 58 | 110 | 102 | [INFO] [stdout] | 16 | 26 | 46 | 42 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A matrix multiplied by a tuple  features/matrices.feature:78:11 [INFO] [stdout]  - Given the following matrix A:  features/matrices.feature:79:3 [INFO] [stdout]  | 1 | 2 | 3 | 4 | [INFO] [stdout] | 2 | 4 | 4 | 2 | [INFO] [stdout] | 8 | 6 | 4 | 1 | [INFO] [stdout] | 0 | 0 | 0 | 1 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And b ← tuple(1, 2, 3, 1)  features/matrices.feature:84:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then A * b = tuple(18, 24, 33, 1)  features/matrices.feature:85:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Multiplying a matrix by the identity matrix [INFO] [stdout]  features/matrices.feature:87:11 [INFO] [stdout]  - Given the following matrix A:  features/matrices.feature:88:3 [INFO] [stdout]  | 0 | 1 | 2 | 4 | [INFO] [stdout] | 1 | 2 | 4 | 8 | [INFO] [stdout] | 2 | 4 | 8 | 16 | [INFO] [stdout] | 4 | 8 | 16 | 32 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then A * identity_matrix = A  features/matrices.feature:93:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Multiplying the identity matrix by a tuple [INFO] [stdout]  features/matrices.feature:95:11 [INFO] [stdout]  - Given a ← tuple(1, 2, 3, 4)  features/matrices.feature:96:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then identity_matrix * a = a  features/matrices.feature:97:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Transposing a matrix  features/matrices.feature:99:11 [INFO] [stdout]  - Given the following matrix A:  features/matrices.feature:100:3 [INFO] [stdout]  | 0 | 9 | 3 | 0 | [INFO] [stdout] | 9 | 8 | 0 | 8 | [INFO] [stdout] | 1 | 8 | 5 | 3 | [INFO] [stdout] | 0 | 0 | 5 | 8 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then transpose(A) is the following matrix:  features/matrices.feature:105:3 [INFO] [stdout]  | 0 | 9 | 1 | 0 | [INFO] [stdout] | 9 | 8 | 8 | 0 | [INFO] [stdout] | 3 | 0 | 5 | 5 | [INFO] [stdout] | 0 | 8 | 3 | 8 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Transposing the identity matrix  features/matrices.feature:111:11 [INFO] [stdout]  - Given A ← transpose(identity_matrix)  features/matrices.feature:112:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then A = identity_matrix  features/matrices.feature:113:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Calculating the determinant of a 2x2 matrix [INFO] [stdout]  features/matrices.feature:115:11 [INFO] [stdout]  - Given the following 2x2 matrix A:  features/matrices.feature:116:3 [INFO] [stdout]  | 1 | 5 | [INFO] [stdout] | -3 | 2 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then determinant(A) = 17  features/matrices.feature:119:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A submatrix of a 3x3 matrix is a 2x2 matrix [INFO] [stdout]  features/matrices.feature:121:11 [INFO] [stdout]  - Given the following 3x3 matrix A:  features/matrices.feature:122:3 [INFO] [stdout]  | 1 | 5 | 0 | [INFO] [stdout] | -3 | 2 | 7 | [INFO] [stdout] | 0 | 6 | -3 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then submatrix(A, 0, 2) is the following 2x2 matrix: [INFO] [stdout]  features/matrices.feature:126:3 [INFO] [stdout]  | -3 | 2 | [INFO] [stdout] | 0 | 6 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A submatrix of a 4x4 matrix is a 3x3 matrix [INFO] [stdout]  features/matrices.feature:130:11 [INFO] [stdout]  - Given the following 4x4 matrix A:  features/matrices.feature:131:3 [INFO] [stdout]  | -6 | 1 | 1 | 6 | [INFO] [stdout] | -8 | 5 | 8 | 6 | [INFO] [stdout] | -1 | 0 | 8 | 2 | [INFO] [stdout] | -7 | 1 | -1 | 1 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then submatrix(A, 2, 1) is the following 3x3 matrix: [INFO] [stdout]  features/matrices.feature:136:3 [INFO] [stdout]  | -6 | 1 | 6 | [INFO] [stdout] | -8 | 8 | 6 | [INFO] [stdout] | -7 | -1 | 1 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Calculating a minor of a 3x3 matrix features/matrices.feature:141:11 [INFO] [stdout]  - Given the following 3x3 matrix A:  features/matrices.feature:142:3 [INFO] [stdout]  | 3 | 5 | 0 | [INFO] [stdout] | 2 | -1 | -7 | [INFO] [stdout] | 6 | -1 | 5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And B ← submatrix(A, 1, 0)  features/matrices.feature:146:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then determinant(B) = 25  features/matrices.feature:147:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And minor(A, 1, 0) = 25  features/matrices.feature:148:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Calculating a cofactor of a 3x3 matrix [INFO] [stdout]  features/matrices.feature:150:11 [INFO] [stdout]  - Given the following 3x3 matrix A:  features/matrices.feature:151:3 [INFO] [stdout]  | 3 | 5 | 0 | [INFO] [stdout] | 2 | -1 | -7 | [INFO] [stdout] | 6 | -1 | 5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then minor(A, 0, 0) = -12  features/matrices.feature:155:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cofactor(A, 0, 0) = -12  features/matrices.feature:156:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And minor(A, 1, 0) = 25  features/matrices.feature:157:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cofactor(A, 1, 0) = -25  features/matrices.feature:158:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Calculating the determinant of a 3x3 matrix [INFO] [stdout]  features/matrices.feature:160:11 [INFO] [stdout]  - Given the following 3x3 matrix A:  features/matrices.feature:161:3 [INFO] [stdout]  | 1 | 2 | 6 | [INFO] [stdout] | -5 | 8 | -4 | [INFO] [stdout] | 2 | 6 | 4 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then cofactor(A, 0, 0) = 56  features/matrices.feature:165:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cofactor(A, 0, 1) = 12  features/matrices.feature:166:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cofactor(A, 0, 2) = -46  features/matrices.feature:167:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And determinant(A) = -196  features/matrices.feature:168:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Calculating the determinant of a 4x4 matrix [INFO] [stdout]  features/matrices.feature:170:11 [INFO] [stdout]  - Given the following 4x4 matrix A:  features/matrices.feature:171:3 [INFO] [stdout]  | -2 | -8 | 3 | 5 | [INFO] [stdout] | -3 | 1 | 7 | 3 | [INFO] [stdout] | 1 | 2 | -9 | 6 | [INFO] [stdout] | -6 | 7 | 7 | -9 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then cofactor(A, 0, 0) = 690  features/matrices.feature:176:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cofactor(A, 0, 1) = 447  features/matrices.feature:177:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cofactor(A, 0, 2) = 210  features/matrices.feature:178:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cofactor(A, 0, 3) = 51  features/matrices.feature:179:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And determinant(A) = -4071  features/matrices.feature:180:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Testing an invertible matrix for invertibility [INFO] [stdout]  features/matrices.feature:182:11 [INFO] [stdout]  - Given the following 4x4 matrix A:  features/matrices.feature:183:3 [INFO] [stdout]  | 6 | 4 | 4 | 4 | [INFO] [stdout] | 5 | 5 | 7 | 6 | [INFO] [stdout] | 4 | -9 | 3 | -7 | [INFO] [stdout] | 9 | 1 | 7 | -6 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then determinant(A) = -2120  features/matrices.feature:188:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And A is invertible  features/matrices.feature:189:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Testing a noninvertible matrix for invertibility [INFO] [stdout]  features/matrices.feature:191:11 [INFO] [stdout]  - Given the following 4x4 matrix A:  features/matrices.feature:192:3 [INFO] [stdout]  | -4 | 2 | -2 | -3 | [INFO] [stdout] | 9 | 6 | 2 | 6 | [INFO] [stdout] | 0 | -5 | 1 | -5 | [INFO] [stdout] | 0 | 0 | 0 | 0 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then determinant(A) = 0  features/matrices.feature:197:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And A is not invertible  features/matrices.feature:198:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Calculating the inverse of a matrix features/matrices.feature:200:11 [INFO] [stdout]  - Given the following 4x4 matrix A:  features/matrices.feature:201:3 [INFO] [stdout]  | -5 | 2 | 6 | -8 | [INFO] [stdout] | 1 | -5 | 1 | 8 | [INFO] [stdout] | 7 | 7 | -6 | -7 | [INFO] [stdout] | 1 | -3 | 7 | 4 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And B ← inverse(A)  features/matrices.feature:206:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then determinant(A) = 532  features/matrices.feature:207:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cofactor(A, 2, 3) = -160  features/matrices.feature:208:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And B[3,2] = -160/532  features/matrices.feature:209:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cofactor(A, 3, 2) = 105  features/matrices.feature:210:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And B[2,3] = 105/532  features/matrices.feature:211:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And B is the following 4x4 matrix:  features/matrices.feature:212:5 [INFO] [stdout]  | 0.21805 | 0.45113 | 0.24060 | -0.04511 | [INFO] [stdout] | -0.80827 | -1.45677 | -0.44361 | 0.52068 | [INFO] [stdout] | -0.07895 | -0.22368 | -0.05263 | 0.19737 | [INFO] [stdout] | -0.52256 | -0.81391 | -0.30075 | 0.30639 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Calculating the inverse of another matrix [INFO] [stdout]  features/matrices.feature:218:11 [INFO] [stdout]  - Given the following 4x4 matrix A:  features/matrices.feature:219:3 [INFO] [stdout]  | 8 | -5 | 9 | 2 | [INFO] [stdout] | 7 | 5 | 6 | 1 | [INFO] [stdout] | -6 | 0 | 9 | 6 | [INFO] [stdout] | -3 | 0 | -9 | -4 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then inverse(A) is the following 4x4 matrix: [INFO] [stdout]  features/matrices.feature:224:3 [INFO] [stdout]  | -0.15385 | -0.15385 | -0.28205 | -0.53846 | [INFO] [stdout] | -0.07692 | 0.12308 | 0.02564 | 0.03077 | [INFO] [stdout] | 0.35897 | 0.35897 | 0.43590 | 0.92308 | [INFO] [stdout] | -0.69231 | -0.69231 | -0.76923 | -1.92308 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Calculating the inverse of a third matrix [INFO] [stdout]  features/matrices.feature:230:11 [INFO] [stdout]  - Given the following 4x4 matrix A:  features/matrices.feature:231:3 [INFO] [stdout]  | 9 | 3 | 0 | 9 | [INFO] [stdout] | -5 | -2 | -6 | -3 | [INFO] [stdout] | -4 | 9 | 6 | 4 | [INFO] [stdout] | -7 | 6 | 6 | 2 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then inverse(A) is the following 4x4 matrix: [INFO] [stdout]  features/matrices.feature:236:3 [INFO] [stdout]  | -0.04074 | -0.07778 | 0.14444 | -0.22222 | [INFO] [stdout] | -0.07778 | 0.03333 | 0.36667 | -0.33333 | [INFO] [stdout] | -0.02901 | -0.14630 | -0.10926 | 0.12963 | [INFO] [stdout] | 0.17778 | 0.06667 | -0.26667 | 0.33333 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Multiplying a product by its inverse [INFO] [stdout]  features/matrices.feature:242:11 [INFO] [stdout]  - Given the following 4x4 matrix A:  features/matrices.feature:243:3 [INFO] [stdout]  | 3 | -9 | 7 | 3 | [INFO] [stdout] | 3 | -8 | 2 | -9 | [INFO] [stdout] | -4 | 4 | 4 | 1 | [INFO] [stdout] | -6 | 5 | -1 | 1 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And the following 4x4 matrix B:  features/matrices.feature:248:5 [INFO] [stdout]  | 8 | 2 | 2 | 2 | [INFO] [stdout] | 3 | -1 | 7 | 0 | [INFO] [stdout] | 7 | 0 | 5 | 4 | [INFO] [stdout] | 6 | -2 | 0 | 5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And C ← A * B  features/matrices.feature:253:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then C * inverse(B) = A  features/matrices.feature:254:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: OBJ File Parser  features/obj_file.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: Ignoring unrecognized lines  features/obj_file.feature:3:11 [INFO] [stdout]  - Given gibberish ← a file containing:  features/obj_file.feature:4:3 [INFO] [stdout]  """ [INFO] [stdout]  There was a young lady named Bright [INFO] [stdout] who traveled much faster than light. [INFO] [stdout] She set out one day [INFO] [stdout] in a relative way, [INFO] [stdout] and came back the previous night. [INFO] [stdout]  """ [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When parser ← parse_obj_file(gibberish)  features/obj_file.feature:12:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then parser should have ignored 5 lines  features/obj_file.feature:13:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Vertex records  features/obj_file.feature:15:11 [INFO] [stdout]  - Given file ← a file containing:  features/obj_file.feature:16:3 [INFO] [stdout]  """ [INFO] [stdout]  v -1 1 0 [INFO] [stdout] v -1.0000 0.5000 0.0000 [INFO] [stdout] v 1 0 0 [INFO] [stdout] v 1 1 0 [INFO] [stdout]  """ [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When parser ← parse_obj_file(file)  features/obj_file.feature:23:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then parser.vertices[1] = point(-1, 1, 0)  features/obj_file.feature:24:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And parser.vertices[2] = point(-1, 0.5, 0)  features/obj_file.feature:25:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And parser.vertices[3] = point(1, 0, 0)  features/obj_file.feature:26:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And parser.vertices[4] = point(1, 1, 0)  features/obj_file.feature:27:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Parsing triangle faces  features/obj_file.feature:29:11 [INFO] [stdout]  - Given file ← a file containing:  features/obj_file.feature:30:3 [INFO] [stdout]  """ [INFO] [stdout]  v -1 1 0 [INFO] [stdout] v -1 0 0 [INFO] [stdout] v 1 0 0 [INFO] [stdout] v 1 1 0 [INFO] [stdout] [INFO] [stdout] f 1 2 3 [INFO] [stdout] f 1 3 4 [INFO] [stdout]  """ [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When parser ← parse_obj_file(file)  features/obj_file.feature:40:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And g ← parser.default_group  features/obj_file.feature:41:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t1 ← first child of g  features/obj_file.feature:42:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t2 ← second child of g  features/obj_file.feature:43:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then t1.p1 = parser.vertices[1]  features/obj_file.feature:44:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t1.p2 = parser.vertices[2]  features/obj_file.feature:45:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t1.p3 = parser.vertices[3]  features/obj_file.feature:46:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t2.p1 = parser.vertices[1]  features/obj_file.feature:47:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t2.p2 = parser.vertices[3]  features/obj_file.feature:48:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t2.p3 = parser.vertices[4]  features/obj_file.feature:49:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Triangulating polygons  features/obj_file.feature:51:11 [INFO] [stdout]  - Given file ← a file containing:  features/obj_file.feature:52:3 [INFO] [stdout]  """ [INFO] [stdout]  v -1 1 0 [INFO] [stdout] v -1 0 0 [INFO] [stdout] v 1 0 0 [INFO] [stdout] v 1 1 0 [INFO] [stdout] v 0 2 0 [INFO] [stdout] [INFO] [stdout] f 1 2 3 4 5 [INFO] [stdout]  """ [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When parser ← parse_obj_file(file)  features/obj_file.feature:62:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And g ← parser.default_group  features/obj_file.feature:63:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t1 ← first child of g  features/obj_file.feature:64:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t2 ← second child of g  features/obj_file.feature:65:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t3 ← third child of g  features/obj_file.feature:66:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then t1.p1 = parser.vertices[1]  features/obj_file.feature:67:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t1.p2 = parser.vertices[2]  features/obj_file.feature:68:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t1.p3 = parser.vertices[3]  features/obj_file.feature:69:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t2.p1 = parser.vertices[1]  features/obj_file.feature:70:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t2.p2 = parser.vertices[3]  features/obj_file.feature:71:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t2.p3 = parser.vertices[4]  features/obj_file.feature:72:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t3.p1 = parser.vertices[1]  features/obj_file.feature:73:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t3.p2 = parser.vertices[4]  features/obj_file.feature:74:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t3.p3 = parser.vertices[5]  features/obj_file.feature:75:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Triangles in groups  features/obj_file.feature:77:11 [INFO] [stdout]  - Given file ← the file "triangles.obj"  features/obj_file.feature:78:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When parser ← parse_obj_file(file)  features/obj_file.feature:79:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And g1 ← "FirstGroup" from parser  features/obj_file.feature:80:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And g2 ← "SecondGroup" from parser  features/obj_file.feature:81:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t1 ← first child of g1  features/obj_file.feature:82:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t2 ← first child of g2  features/obj_file.feature:83:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then t1.p1 = parser.vertices[1]  features/obj_file.feature:84:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t1.p2 = parser.vertices[2]  features/obj_file.feature:85:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t1.p3 = parser.vertices[3]  features/obj_file.feature:86:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t2.p1 = parser.vertices[1]  features/obj_file.feature:87:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t2.p2 = parser.vertices[3]  features/obj_file.feature:88:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t2.p3 = parser.vertices[4]  features/obj_file.feature:89:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Converting an OBJ file to a group  features/obj_file.feature:91:11 [INFO] [stdout]  - Given file ← the file "triangles.obj"  features/obj_file.feature:92:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And parser ← parse_obj_file(file)  features/obj_file.feature:93:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When g ← obj_to_group(parser)  features/obj_file.feature:94:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then g includes "FirstGroup" from parser  features/obj_file.feature:95:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And g includes "SecondGroup" from parser  features/obj_file.feature:96:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Vertex normal records  features/obj_file.feature:98:11 [INFO] [stdout]  - Given file ← a file containing:  features/obj_file.feature:99:3 [INFO] [stdout]  """ [INFO] [stdout]  vn 0 0 1 [INFO] [stdout] vn 0.707 0 -0.707 [INFO] [stdout] vn 1 2 3 [INFO] [stdout]  """ [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When parser ← parse_obj_file(file)  features/obj_file.feature:105:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then parser.normals[1] = vector(0, 0, 1)  features/obj_file.feature:106:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And parser.normals[2] = vector(0.707, 0, -0.707) [INFO] [stdout]  features/obj_file.feature:107:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And parser.normals[3] = vector(1, 2, 3)  features/obj_file.feature:108:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Faces with normals  features/obj_file.feature:110:11 [INFO] [stdout]  - Given file ← a file containing:  features/obj_file.feature:111:3 [INFO] [stdout]  """ [INFO] [stdout]  v 0 1 0 [INFO] [stdout] v -1 0 0 [INFO] [stdout] v 1 0 0 [INFO] [stdout] [INFO] [stdout] vn -1 0 0 [INFO] [stdout] vn 1 0 0 [INFO] [stdout] vn 0 1 0 [INFO] [stdout] [INFO] [stdout] f 1//3 2//1 3//2 [INFO] [stdout] f 1/0/3 2/102/1 3/14/2 [INFO] [stdout]  """ [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When parser ← parse_obj_file(file)  features/obj_file.feature:124:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And g ← parser.default_group  features/obj_file.feature:125:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t1 ← first child of g  features/obj_file.feature:126:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t2 ← second child of g  features/obj_file.feature:127:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then t1.p1 = parser.vertices[1]  features/obj_file.feature:128:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t1.p2 = parser.vertices[2]  features/obj_file.feature:129:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t1.p3 = parser.vertices[3]  features/obj_file.feature:130:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t1.n1 = parser.normals[3]  features/obj_file.feature:131:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t1.n2 = parser.normals[1]  features/obj_file.feature:132:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t1.n3 = parser.normals[2]  features/obj_file.feature:133:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t2 = t1  features/obj_file.feature:134:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: Patterns  features/patterns.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: Creating a stripe pattern  features/patterns.feature:7:11 [INFO] [stdout]  - Given black ← color(0, 0, 0)  features/patterns.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And white ← color(1, 1, 1)  features/patterns.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given pattern ← stripe_pattern(white, black)  features/patterns.feature:8:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then pattern.a = white  features/patterns.feature:9:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And pattern.b = black  features/patterns.feature:10:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A stripe pattern is constant in y  features/patterns.feature:12:11 [INFO] [stdout]  - Given black ← color(0, 0, 0)  features/patterns.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And white ← color(1, 1, 1)  features/patterns.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given pattern ← stripe_pattern(white, black) features/patterns.feature:13:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then stripe_at(pattern, point(0, 0, 0)) = white [INFO] [stdout]  features/patterns.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And stripe_at(pattern, point(0, 1, 0)) = white [INFO] [stdout]  features/patterns.feature:15:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And stripe_at(pattern, point(0, 2, 0)) = white [INFO] [stdout]  features/patterns.feature:16:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A stripe pattern is constant in z  features/patterns.feature:18:11 [INFO] [stdout]  - Given black ← color(0, 0, 0)  features/patterns.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And white ← color(1, 1, 1)  features/patterns.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given pattern ← stripe_pattern(white, black) features/patterns.feature:19:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then stripe_at(pattern, point(0, 0, 0)) = white [INFO] [stdout]  features/patterns.feature:20:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And stripe_at(pattern, point(0, 0, 1)) = white [INFO] [stdout]  features/patterns.feature:21:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And stripe_at(pattern, point(0, 0, 2)) = white [INFO] [stdout]  features/patterns.feature:22:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A stripe pattern alternates in x  features/patterns.feature:24:11 [INFO] [stdout]  - Given black ← color(0, 0, 0)  features/patterns.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And white ← color(1, 1, 1)  features/patterns.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given pattern ← stripe_pattern(white, black) features/patterns.feature:25:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then stripe_at(pattern, point(0, 0, 0)) = white [INFO] [stdout]  features/patterns.feature:26:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And stripe_at(pattern, point(0.9, 0, 0)) = white [INFO] [stdout]  features/patterns.feature:27:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And stripe_at(pattern, point(1, 0, 0)) = black [INFO] [stdout]  features/patterns.feature:28:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And stripe_at(pattern, point(-0.1, 0, 0)) = black [INFO] [stdout]  features/patterns.feature:29:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And stripe_at(pattern, point(-1, 0, 0)) = black [INFO] [stdout]  features/patterns.feature:30:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And stripe_at(pattern, point(-1.1, 0, 0)) = white [INFO] [stdout]  features/patterns.feature:31:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Stripes with an object transformation [INFO] [stdout]  features/patterns.feature:33:11 [INFO] [stdout]  - Given black ← color(0, 0, 0)  features/patterns.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And white ← color(1, 1, 1)  features/patterns.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given object ← sphere()  features/patterns.feature:34:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(object, scaling(2, 2, 2))  features/patterns.feature:35:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And pattern ← stripe_pattern(white, black)  features/patterns.feature:36:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When c ← stripe_at_object(pattern, object, point(1.5, 0, 0)) [INFO] [stdout]  features/patterns.feature:37:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c = white  features/patterns.feature:38:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Stripes with a pattern transformation [INFO] [stdout]  features/patterns.feature:40:11 [INFO] [stdout]  - Given black ← color(0, 0, 0)  features/patterns.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And white ← color(1, 1, 1)  features/patterns.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given object ← sphere()  features/patterns.feature:41:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And pattern ← stripe_pattern(white, black)  features/patterns.feature:42:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_pattern_transform(pattern, scaling(2, 2, 2)) [INFO] [stdout]  features/patterns.feature:43:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When c ← stripe_at_object(pattern, object, point(1.5, 0, 0)) [INFO] [stdout]  features/patterns.feature:44:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c = white  features/patterns.feature:45:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Stripes with both an object and a pattern transformation [INFO] [stdout]  features/patterns.feature:47:11 [INFO] [stdout]  - Given black ← color(0, 0, 0)  features/patterns.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And white ← color(1, 1, 1)  features/patterns.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given object ← sphere()  features/patterns.feature:48:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(object, scaling(2, 2, 2))  features/patterns.feature:49:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And pattern ← stripe_pattern(white, black)  features/patterns.feature:50:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_pattern_transform(pattern, translation(0.5, 0, 0)) [INFO] [stdout]  features/patterns.feature:51:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When c ← stripe_at_object(pattern, object, point(2.5, 0, 0)) [INFO] [stdout]  features/patterns.feature:52:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c = white  features/patterns.feature:53:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The default pattern transformation  features/patterns.feature:55:11 [INFO] [stdout]  - Given black ← color(0, 0, 0)  features/patterns.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And white ← color(1, 1, 1)  features/patterns.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given pattern ← test_pattern()  features/patterns.feature:56:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then pattern.transform = identity_matrix  features/patterns.feature:57:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Assigning a transformation  features/patterns.feature:59:11 [INFO] [stdout]  - Given black ← color(0, 0, 0)  features/patterns.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And white ← color(1, 1, 1)  features/patterns.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given pattern ← test_pattern()  features/patterns.feature:60:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When set_pattern_transform(pattern, translation(1, 2, 3)) [INFO] [stdout]  features/patterns.feature:61:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then pattern.transform = translation(1, 2, 3) [INFO] [stdout]  features/patterns.feature:62:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A pattern with an object transformation [INFO] [stdout]  features/patterns.feature:64:11 [INFO] [stdout]  - Given black ← color(0, 0, 0)  features/patterns.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And white ← color(1, 1, 1)  features/patterns.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given shape ← sphere()  features/patterns.feature:65:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(shape, scaling(2, 2, 2))  features/patterns.feature:66:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And pattern ← test_pattern()  features/patterns.feature:67:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When c ← pattern_at_shape(pattern, shape, point(2, 3, 4)) [INFO] [stdout]  features/patterns.feature:68:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c = color(1, 1.5, 2)  features/patterns.feature:69:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A pattern with a pattern transformation [INFO] [stdout]  features/patterns.feature:71:11 [INFO] [stdout]  - Given black ← color(0, 0, 0)  features/patterns.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And white ← color(1, 1, 1)  features/patterns.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given shape ← sphere()  features/patterns.feature:72:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And pattern ← test_pattern()  features/patterns.feature:73:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_pattern_transform(pattern, scaling(2, 2, 2)) [INFO] [stdout]  features/patterns.feature:74:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When c ← pattern_at_shape(pattern, shape, point(2, 3, 4)) [INFO] [stdout]  features/patterns.feature:75:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c = color(1, 1.5, 2)  features/patterns.feature:76:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A pattern with both an object and a pattern transformation [INFO] [stdout]  features/patterns.feature:78:11 [INFO] [stdout]  - Given black ← color(0, 0, 0)  features/patterns.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And white ← color(1, 1, 1)  features/patterns.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given shape ← sphere()  features/patterns.feature:79:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(shape, scaling(2, 2, 2))  features/patterns.feature:80:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And pattern ← test_pattern()  features/patterns.feature:81:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_pattern_transform(pattern, translation(0.5, 1, 1.5)) [INFO] [stdout]  features/patterns.feature:82:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When c ← pattern_at_shape(pattern, shape, point(2.5, 3, 3.5)) [INFO] [stdout]  features/patterns.feature:83:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c = color(0.75, 0.5, 0.25)  features/patterns.feature:84:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A gradient linearly interpolates between colors [INFO] [stdout]  features/patterns.feature:86:11 [INFO] [stdout]  - Given black ← color(0, 0, 0)  features/patterns.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And white ← color(1, 1, 1)  features/patterns.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given pattern ← gradient_pattern(white, black) [INFO] [stdout]  features/patterns.feature:87:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then pattern_at(pattern, point(0, 0, 0)) = white [INFO] [stdout]  features/patterns.feature:88:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And pattern_at(pattern, point(0.25, 0, 0)) = color(0.75, 0.75, 0.75) [INFO] [stdout]  features/patterns.feature:89:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And pattern_at(pattern, point(0.5, 0, 0)) = color(0.5, 0.5, 0.5) [INFO] [stdout]  features/patterns.feature:90:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And pattern_at(pattern, point(0.75, 0, 0)) = color(0.25, 0.25, 0.25) [INFO] [stdout]  features/patterns.feature:91:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ring should extend in both x and z features/patterns.feature:93:11 [INFO] [stdout]  - Given black ← color(0, 0, 0)  features/patterns.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And white ← color(1, 1, 1)  features/patterns.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given pattern ← ring_pattern(white, black)  features/patterns.feature:94:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then pattern_at(pattern, point(0, 0, 0)) = white [INFO] [stdout]  features/patterns.feature:95:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And pattern_at(pattern, point(1, 0, 0)) = black [INFO] [stdout]  features/patterns.feature:96:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And pattern_at(pattern, point(0, 0, 1)) = black [INFO] [stdout]  features/patterns.feature:97:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And pattern_at(pattern, point(0.708, 0, 0.708)) = black [INFO] [stdout]  features/patterns.feature:99:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Checkers should repeat in x  features/patterns.feature:101:11 [INFO] [stdout]  - Given black ← color(0, 0, 0)  features/patterns.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And white ← color(1, 1, 1)  features/patterns.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given pattern ← checkers_pattern(white, black) [INFO] [stdout]  features/patterns.feature:102:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then pattern_at(pattern, point(0, 0, 0)) = white [INFO] [stdout]  features/patterns.feature:103:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And pattern_at(pattern, point(0.99, 0, 0)) = white [INFO] [stdout]  features/patterns.feature:104:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And pattern_at(pattern, point(1.01, 0, 0)) = black [INFO] [stdout]  features/patterns.feature:105:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Checkers should repeat in y  features/patterns.feature:107:11 [INFO] [stdout]  - Given black ← color(0, 0, 0)  features/patterns.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And white ← color(1, 1, 1)  features/patterns.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given pattern ← checkers_pattern(white, black) [INFO] [stdout]  features/patterns.feature:108:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then pattern_at(pattern, point(0, 0, 0)) = white [INFO] [stdout]  features/patterns.feature:109:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And pattern_at(pattern, point(0, 0.99, 0)) = white [INFO] [stdout]  features/patterns.feature:110:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And pattern_at(pattern, point(0, 1.01, 0)) = black [INFO] [stdout]  features/patterns.feature:111:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Checkers should repeat in z  features/patterns.feature:113:11 [INFO] [stdout]  - Given black ← color(0, 0, 0)  features/patterns.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And white ← color(1, 1, 1)  features/patterns.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Given pattern ← checkers_pattern(white, black) [INFO] [stdout]  features/patterns.feature:114:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then pattern_at(pattern, point(0, 0, 0)) = white [INFO] [stdout]  features/patterns.feature:115:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And pattern_at(pattern, point(0, 0, 0.99)) = white [INFO] [stdout]  features/patterns.feature:116:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And pattern_at(pattern, point(0, 0, 1.01)) = black [INFO] [stdout]  features/patterns.feature:117:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: Planes  features/planes.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: The normal of a plane is constant everywhere [INFO] [stdout]  features/planes.feature:3:11 [INFO] [stdout]  - Given p ← plane()  features/planes.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n1 ← local_normal_at(p, point(0, 0, 0))  features/planes.feature:5:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n2 ← local_normal_at(p, point(10, 0, -10))  features/planes.feature:6:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n3 ← local_normal_at(p, point(-5, 0, 150))  features/planes.feature:7:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n1 = vector(0, 1, 0)  features/planes.feature:8:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n2 = vector(0, 1, 0)  features/planes.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n3 = vector(0, 1, 0)  features/planes.feature:10:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersect with a ray parallel to the plane [INFO] [stdout]  features/planes.feature:12:11 [INFO] [stdout]  - Given p ← plane()  features/planes.feature:13:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 10, 0), vector(0, 0, 1))  features/planes.feature:14:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(p, r)  features/planes.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs is empty  features/planes.feature:16:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersect with a coplanar ray  features/planes.feature:18:11 [INFO] [stdout]  - Given p ← plane()  features/planes.feature:19:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, 0), vector(0, 0, 1))  features/planes.feature:20:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(p, r)  features/planes.feature:21:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs is empty  features/planes.feature:22:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray intersecting a plane from above  features/planes.feature:24:11 [INFO] [stdout]  - Given p ← plane()  features/planes.feature:25:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 1, 0), vector(0, -1, 0))  features/planes.feature:26:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(p, r)  features/planes.feature:27:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 1  features/planes.feature:28:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = 1  features/planes.feature:29:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].object = p  features/planes.feature:30:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray intersecting a plane from below  features/planes.feature:32:11 [INFO] [stdout]  - Given p ← plane()  features/planes.feature:33:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, -1, 0), vector(0, 1, 0))  features/planes.feature:34:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(p, r)  features/planes.feature:35:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 1  features/planes.feature:36:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = 1  features/planes.feature:37:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].object = p  features/planes.feature:38:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: Rays  features/rays.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: Creating and querying a ray  features/rays.feature:3:11 [INFO] [stdout]  - Given origin ← point(1, 2, 3)  features/rays.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And direction ← vector(4, 5, 6)  features/rays.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When r ← ray(origin, direction)  features/rays.feature:6:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then r.origin = origin  features/rays.feature:7:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r.direction = direction  features/rays.feature:8:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Computing a point from a distance  features/rays.feature:10:11 [INFO] [stdout]  - Given r ← ray(point(2, 3, 4), vector(1, 0, 0))  features/rays.feature:11:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then position(r, 0) = point(2, 3, 4)  features/rays.feature:12:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And position(r, 1) = point(3, 3, 4)  features/rays.feature:13:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And position(r, -1) = point(1, 3, 4)  features/rays.feature:14:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And position(r, 2.5) = point(4.5, 3, 4)  features/rays.feature:15:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Translating a ray  features/rays.feature:17:11 [INFO] [stdout]  - Given r ← ray(point(1, 2, 3), vector(0, 1, 0))  features/rays.feature:18:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And m ← translation(3, 4, 5)  features/rays.feature:19:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When r2 ← transform(r, m)  features/rays.feature:20:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then r2.origin = point(4, 6, 8)  features/rays.feature:21:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r2.direction = vector(0, 1, 0)  features/rays.feature:22:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Scaling a ray  features/rays.feature:24:11 [INFO] [stdout]  - Given r ← ray(point(1, 2, 3), vector(0, 1, 0))  features/rays.feature:25:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And m ← scaling(2, 3, 4)  features/rays.feature:26:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When r2 ← transform(r, m)  features/rays.feature:27:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then r2.origin = point(2, 6, 12)  features/rays.feature:28:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r2.direction = vector(0, 3, 0)  features/rays.feature:29:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: Abstract Shapes  features/shapes.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: The default transformation  features/shapes.feature:3:11 [INFO] [stdout]  - Given s ← test_shape()  features/shapes.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then s.transform = identity_matrix  features/shapes.feature:5:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Assigning a transformation  features/shapes.feature:7:11 [INFO] [stdout]  - Given s ← test_shape()  features/shapes.feature:8:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When set_transform(s, translation(2, 3, 4))  features/shapes.feature:9:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then s.transform = translation(2, 3, 4)  features/shapes.feature:10:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The default material  features/shapes.feature:12:11 [INFO] [stdout]  - Given s ← test_shape()  features/shapes.feature:13:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When m ← s.material  features/shapes.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then m = material()  features/shapes.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Assigning a material  features/shapes.feature:17:11 [INFO] [stdout]  - Given s ← test_shape()  features/shapes.feature:18:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And m ← material()  features/shapes.feature:19:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And m.ambient ← 1  features/shapes.feature:20:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When s.material ← m  features/shapes.feature:21:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then s.material = m  features/shapes.feature:22:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a scaled shape with a ray features/shapes.feature:24:11 [INFO] [stdout]  - Given r ← ray(point(0, 0, -5), vector(0, 0, 1)) [INFO] [stdout]  features/shapes.feature:25:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s ← test_shape()  features/shapes.feature:26:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When set_transform(s, scaling(2, 2, 2))  features/shapes.feature:27:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersect(s, r)  features/shapes.feature:28:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then s.saved_ray.origin = point(0, 0, -2.5)  features/shapes.feature:29:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s.saved_ray.direction = vector(0, 0, 0.5)  features/shapes.feature:30:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a translated shape with a ray [INFO] [stdout]  features/shapes.feature:32:11 [INFO] [stdout]  - Given r ← ray(point(0, 0, -5), vector(0, 0, 1)) [INFO] [stdout]  features/shapes.feature:33:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s ← test_shape()  features/shapes.feature:34:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When set_transform(s, translation(5, 0, 0))  features/shapes.feature:35:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersect(s, r)  features/shapes.feature:36:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then s.saved_ray.origin = point(-5, 0, -5)  features/shapes.feature:37:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s.saved_ray.direction = vector(0, 0, 1)  features/shapes.feature:38:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Computing the normal on a translated shape [INFO] [stdout]  features/shapes.feature:40:11 [INFO] [stdout]  - Given s ← test_shape()  features/shapes.feature:41:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When set_transform(s, translation(0, 1, 0))  features/shapes.feature:42:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n ← normal_at(s, point(0, 1.70711, -0.70711)) [INFO] [stdout]  features/shapes.feature:43:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(0, 0.70711, -0.70711)  features/shapes.feature:44:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Computing the normal on a transformed shape [INFO] [stdout]  features/shapes.feature:46:11 [INFO] [stdout]  - Given s ← test_shape()  features/shapes.feature:47:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And m ← scaling(1, 0.5, 1) * rotation_z(π/5)  features/shapes.feature:48:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When set_transform(s, m)  features/shapes.feature:49:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n ← normal_at(s, point(0, √2/2, -√2/2))  features/shapes.feature:50:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(0, 0.97014, -0.24254)  features/shapes.feature:51:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A shape has a parent attribute  features/shapes.feature:53:11 [INFO] [stdout]  - Given s ← test_shape()  features/shapes.feature:54:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then s.parent is nothing  features/shapes.feature:55:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Converting a point from world to object space [INFO] [stdout]  features/shapes.feature:57:11 [INFO] [stdout]  - Given g1 ← group()  features/shapes.feature:58:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(g1, rotation_y(π/2))  features/shapes.feature:59:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And g2 ← group()  features/shapes.feature:60:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(g2, scaling(2, 2, 2))  features/shapes.feature:61:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And add_child(g1, g2)  features/shapes.feature:62:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s ← sphere()  features/shapes.feature:63:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(s, translation(5, 0, 0))  features/shapes.feature:64:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And add_child(g2, s)  features/shapes.feature:65:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When p ← world_to_object(s, point(-2, 0, -10)) features/shapes.feature:66:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then p = point(0, 0, -1)  features/shapes.feature:67:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Converting a normal from object to world space [INFO] [stdout]  features/shapes.feature:69:11 [INFO] [stdout]  - Given g1 ← group()  features/shapes.feature:70:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(g1, rotation_y(π/2))  features/shapes.feature:71:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And g2 ← group()  features/shapes.feature:72:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(g2, scaling(1, 2, 3))  features/shapes.feature:73:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And add_child(g1, g2)  features/shapes.feature:74:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s ← sphere()  features/shapes.feature:75:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(s, translation(5, 0, 0))  features/shapes.feature:76:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And add_child(g2, s)  features/shapes.feature:77:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← normal_to_world(s, vector(√3/3, √3/3, √3/3)) [INFO] [stdout]  features/shapes.feature:78:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(0.2857, 0.4286, -0.8571)  features/shapes.feature:79:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Finding the normal on a child object  features/shapes.feature:81:11 [INFO] [stdout]  - Given g1 ← group()  features/shapes.feature:82:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(g1, rotation_y(π/2))  features/shapes.feature:83:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And g2 ← group()  features/shapes.feature:84:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(g2, scaling(1, 2, 3))  features/shapes.feature:85:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And add_child(g1, g2)  features/shapes.feature:86:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s ← sphere()  features/shapes.feature:87:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(s, translation(5, 0, 0))  features/shapes.feature:88:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And add_child(g2, s)  features/shapes.feature:89:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← normal_at(s, point(1.7321, 1.1547, -5.5774)) [INFO] [stdout]  features/shapes.feature:90:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(0.2857, 0.4286, -0.8571)  features/shapes.feature:91:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: Smooth Triangles  features/smooth-triangles.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: Constructing a smooth triangle [INFO] [stdout]  features/smooth-triangles.feature:12:11 [INFO] [stdout]  - Given p1 ← point(0, 1, 0)  features/smooth-triangles.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p2 ← point(-1, 0, 0)  features/smooth-triangles.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p3 ← point(1, 0, 0)  features/smooth-triangles.feature:6:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n1 ← vector(0, 1, 0)  features/smooth-triangles.feature:7:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n2 ← vector(-1, 0, 0)  features/smooth-triangles.feature:8:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n3 ← vector(1, 0, 0)  features/smooth-triangles.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When tri ← smooth_triangle(p1, p2, p3, n1, n2, n3) [INFO] [stdout]  features/smooth-triangles.feature:10:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then tri.p1 = p1  features/smooth-triangles.feature:13:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And tri.p2 = p2  features/smooth-triangles.feature:14:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And tri.p3 = p3  features/smooth-triangles.feature:15:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And tri.n1 = n1  features/smooth-triangles.feature:16:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And tri.n2 = n2  features/smooth-triangles.feature:17:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And tri.n3 = n3  features/smooth-triangles.feature:18:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: An intersection with a smooth triangle stores u/v [INFO] [stdout]  features/smooth-triangles.feature:20:11 [INFO] [stdout]  - Given p1 ← point(0, 1, 0)  features/smooth-triangles.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p2 ← point(-1, 0, 0)  features/smooth-triangles.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p3 ← point(1, 0, 0)  features/smooth-triangles.feature:6:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n1 ← vector(0, 1, 0)  features/smooth-triangles.feature:7:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n2 ← vector(-1, 0, 0)  features/smooth-triangles.feature:8:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n3 ← vector(1, 0, 0)  features/smooth-triangles.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When tri ← smooth_triangle(p1, p2, p3, n1, n2, n3) [INFO] [stdout]  features/smooth-triangles.feature:10:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When r ← ray(point(-0.2, 0.3, -2), vector(0, 0, 1)) [INFO] [stdout]  features/smooth-triangles.feature:21:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← local_intersect(tri, r)  features/smooth-triangles.feature:22:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs[0].u = 0.45  features/smooth-triangles.feature:23:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].v = 0.25  features/smooth-triangles.feature:24:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A smooth triangle uses u/v to interpolate the normal [INFO] [stdout]  features/smooth-triangles.feature:26:11 [INFO] [stdout]  - Given p1 ← point(0, 1, 0)  features/smooth-triangles.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p2 ← point(-1, 0, 0)  features/smooth-triangles.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p3 ← point(1, 0, 0)  features/smooth-triangles.feature:6:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n1 ← vector(0, 1, 0)  features/smooth-triangles.feature:7:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n2 ← vector(-1, 0, 0)  features/smooth-triangles.feature:8:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n3 ← vector(1, 0, 0)  features/smooth-triangles.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When tri ← smooth_triangle(p1, p2, p3, n1, n2, n3) [INFO] [stdout]  features/smooth-triangles.feature:10:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When i ← intersection_with_uv(1, tri, 0.45, 0.25) [INFO] [stdout]  features/smooth-triangles.feature:27:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n ← normal_at(tri, point(0, 0, 0), i) [INFO] [stdout]  features/smooth-triangles.feature:28:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(-0.5547, 0.83205, 0) features/smooth-triangles.feature:29:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Preparing the normal on a smooth triangle [INFO] [stdout]  features/smooth-triangles.feature:31:11 [INFO] [stdout]  - Given p1 ← point(0, 1, 0)  features/smooth-triangles.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p2 ← point(-1, 0, 0)  features/smooth-triangles.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p3 ← point(1, 0, 0)  features/smooth-triangles.feature:6:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n1 ← vector(0, 1, 0)  features/smooth-triangles.feature:7:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n2 ← vector(-1, 0, 0)  features/smooth-triangles.feature:8:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n3 ← vector(1, 0, 0)  features/smooth-triangles.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When tri ← smooth_triangle(p1, p2, p3, n1, n2, n3) [INFO] [stdout]  features/smooth-triangles.feature:10:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When i ← intersection_with_uv(1, tri, 0.45, 0.25) [INFO] [stdout]  features/smooth-triangles.feature:32:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(-0.2, 0.3, -2), vector(0, 0, 1)) [INFO] [stdout]  features/smooth-triangles.feature:33:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(i)  features/smooth-triangles.feature:34:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And comps ← prepare_computations(i, r, xs) [INFO] [stdout]  features/smooth-triangles.feature:35:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then comps.normalv = vector(-0.5547, 0.83205, 0) [INFO] [stdout]  features/smooth-triangles.feature:36:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: Spheres  features/spheres.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: A ray intersects a sphere at two points [INFO] [stdout]  features/spheres.feature:3:11 [INFO] [stdout]  - Given r ← ray(point(0, 0, -5), vector(0, 0, 1)) [INFO] [stdout]  features/spheres.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s ← sphere()  features/spheres.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← intersect(s, r)  features/spheres.feature:6:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/spheres.feature:7:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0] = 4.0  features/spheres.feature:8:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1] = 6.0  features/spheres.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray intersects a sphere at a tangent [INFO] [stdout]  features/spheres.feature:11:11 [INFO] [stdout]  - Given r ← ray(point(0, 1, -5), vector(0, 0, 1)) [INFO] [stdout]  features/spheres.feature:12:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s ← sphere()  features/spheres.feature:13:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← intersect(s, r)  features/spheres.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/spheres.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0] = 5.0  features/spheres.feature:16:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1] = 5.0  features/spheres.feature:17:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray misses a sphere  features/spheres.feature:19:11 [INFO] [stdout]  - Given r ← ray(point(0, 2, -5), vector(0, 0, 1)) [INFO] [stdout]  features/spheres.feature:20:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s ← sphere()  features/spheres.feature:21:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← intersect(s, r)  features/spheres.feature:22:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 0  features/spheres.feature:23:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray originates inside a sphere  features/spheres.feature:25:11 [INFO] [stdout]  - Given r ← ray(point(0, 0, 0), vector(0, 0, 1)) [INFO] [stdout]  features/spheres.feature:26:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s ← sphere()  features/spheres.feature:27:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← intersect(s, r)  features/spheres.feature:28:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/spheres.feature:29:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0] = -1.0  features/spheres.feature:30:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1] = 1.0  features/spheres.feature:31:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A sphere is behind a ray  features/spheres.feature:33:11 [INFO] [stdout]  - Given r ← ray(point(0, 0, 5), vector(0, 0, 1)) [INFO] [stdout]  features/spheres.feature:34:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s ← sphere()  features/spheres.feature:35:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← intersect(s, r)  features/spheres.feature:36:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/spheres.feature:37:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0] = -6.0  features/spheres.feature:38:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1] = -4.0  features/spheres.feature:39:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersect sets the object on the intersection [INFO] [stdout]  features/spheres.feature:41:11 [INFO] [stdout]  - Given r ← ray(point(0, 0, -5), vector(0, 0, 1)) [INFO] [stdout]  features/spheres.feature:42:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s ← sphere()  features/spheres.feature:43:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← intersect(s, r)  features/spheres.feature:44:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/spheres.feature:45:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].object = s  features/spheres.feature:46:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].object = s  features/spheres.feature:47:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A sphere's default transformation  features/spheres.feature:49:11 [INFO] [stdout]  - Given s ← sphere()  features/spheres.feature:50:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then s.transform = identity_matrix  features/spheres.feature:51:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Changing a sphere's transformation  features/spheres.feature:53:11 [INFO] [stdout]  - Given s ← sphere()  features/spheres.feature:54:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t ← translation(2, 3, 4)  features/spheres.feature:55:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When set_transform(s, t)  features/spheres.feature:56:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then s.transform = t  features/spheres.feature:57:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a scaled sphere with a ray [INFO] [stdout]  features/spheres.feature:59:11 [INFO] [stdout]  - Given r ← ray(point(0, 0, -5), vector(0, 0, 1)) [INFO] [stdout]  features/spheres.feature:60:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s ← sphere()  features/spheres.feature:61:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When set_transform(s, scaling(2, 2, 2))  features/spheres.feature:62:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersect(s, r)  features/spheres.feature:63:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 2  features/spheres.feature:64:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = 3  features/spheres.feature:65:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].t = 7  features/spheres.feature:66:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a translated sphere with a ray [INFO] [stdout]  features/spheres.feature:68:11 [INFO] [stdout]  - Given r ← ray(point(0, 0, -5), vector(0, 0, 1)) [INFO] [stdout]  features/spheres.feature:69:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s ← sphere()  features/spheres.feature:70:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When set_transform(s, translation(5, 0, 0))  features/spheres.feature:71:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersect(s, r)  features/spheres.feature:72:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 0  features/spheres.feature:73:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The normal on a sphere at a point on the x axis [INFO] [stdout]  features/spheres.feature:75:11 [INFO] [stdout]  - Given s ← sphere()  features/spheres.feature:76:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← normal_at(s, point(1, 0, 0))  features/spheres.feature:77:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(1, 0, 0)  features/spheres.feature:78:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The normal on a sphere at a point on the y axis [INFO] [stdout]  features/spheres.feature:80:11 [INFO] [stdout]  - Given s ← sphere()  features/spheres.feature:81:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← normal_at(s, point(0, 1, 0))  features/spheres.feature:82:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(0, 1, 0)  features/spheres.feature:83:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The normal on a sphere at a point on the z axis [INFO] [stdout]  features/spheres.feature:85:11 [INFO] [stdout]  - Given s ← sphere()  features/spheres.feature:86:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← normal_at(s, point(0, 0, 1))  features/spheres.feature:87:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(0, 0, 1)  features/spheres.feature:88:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The normal on a sphere at a nonaxial point [INFO] [stdout]  features/spheres.feature:90:11 [INFO] [stdout]  - Given s ← sphere()  features/spheres.feature:91:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← normal_at(s, point(√3/3, √3/3, √3/3)) [INFO] [stdout]  features/spheres.feature:92:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(√3/3, √3/3, √3/3)  features/spheres.feature:93:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The normal is a normalized vector  features/spheres.feature:95:11 [INFO] [stdout]  - Given s ← sphere()  features/spheres.feature:96:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← normal_at(s, point(√3/3, √3/3, √3/3)) [INFO] [stdout]  features/spheres.feature:97:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = normalize(n)  features/spheres.feature:98:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Computing the normal on a translated sphere [INFO] [stdout]  features/spheres.feature:100:11 [INFO] [stdout]  - Given s ← sphere()  features/spheres.feature:101:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(s, translation(0, 1, 0))  features/spheres.feature:102:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← normal_at(s, point(0, 1.70711, -0.70711)) [INFO] [stdout]  features/spheres.feature:103:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(0, 0.70711, -0.70711)  features/spheres.feature:104:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Computing the normal on a transformed sphere [INFO] [stdout]  features/spheres.feature:106:11 [INFO] [stdout]  - Given s ← sphere()  features/spheres.feature:107:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And m ← scaling(1, 0.5, 1) * rotation_z(π/5) features/spheres.feature:108:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And set_transform(s, m)  features/spheres.feature:109:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n ← normal_at(s, point(0, √2/2, -√2/2)) features/spheres.feature:110:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n = vector(0, 0.97014, -0.24254)  features/spheres.feature:111:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A sphere has a default material  features/spheres.feature:113:11 [INFO] [stdout]  - Given s ← sphere()  features/spheres.feature:114:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When m ← s.material  features/spheres.feature:115:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then m = material()  features/spheres.feature:116:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A sphere may be assigned a material  features/spheres.feature:118:11 [INFO] [stdout]  - Given s ← sphere()  features/spheres.feature:119:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And m ← material()  features/spheres.feature:120:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And m.ambient ← 1  features/spheres.feature:121:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When s.material ← m  features/spheres.feature:122:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then s.material = m  features/spheres.feature:123:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A helper for producing a sphere with a glassy material [INFO] [stdout]  features/spheres.feature:125:11 [INFO] [stdout]  - Given s ← glass_sphere()  features/spheres.feature:126:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then s.transform = identity_matrix  features/spheres.feature:127:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s.material.transparency = 1.0  features/spheres.feature:128:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s.material.refractive_index = 1.5  features/spheres.feature:129:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: Matrix Transformations  features/transformations.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: Multiplying by a translation matrix [INFO] [stdout]  features/transformations.feature:3:11 [INFO] [stdout]  - Given transform ← translation(5, -3, 2) [INFO] [stdout]  features/transformations.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(-3, 4, 5)  features/transformations.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then transform * p = point(2, 1, 7)  features/transformations.feature:6:4 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Multiplying by the inverse of a translation matrix [INFO] [stdout]  features/transformations.feature:8:11 [INFO] [stdout]  - Given transform ← translation(5, -3, 2) [INFO] [stdout]  features/transformations.feature:9:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And inv ← inverse(transform)  features/transformations.feature:10:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(-3, 4, 5)  features/transformations.feature:11:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then inv * p = point(-8, 7, 3)  features/transformations.feature:12:4 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Translation does not affect vectors [INFO] [stdout]  features/transformations.feature:14:11 [INFO] [stdout]  - Given transform ← translation(5, -3, 2) [INFO] [stdout]  features/transformations.feature:15:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And v ← vector(-3, 4, 5)  features/transformations.feature:16:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then transform * v = v  features/transformations.feature:17:4 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A scaling matrix applied to a point [INFO] [stdout]  features/transformations.feature:19:11 [INFO] [stdout]  - Given transform ← scaling(2, 3, 4)  features/transformations.feature:20:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(-4, 6, 8)  features/transformations.feature:21:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then transform * p = point(-8, 18, 32) [INFO] [stdout]  features/transformations.feature:22:4 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A scaling matrix applied to a vector [INFO] [stdout]  features/transformations.feature:24:11 [INFO] [stdout]  - Given transform ← scaling(2, 3, 4)  features/transformations.feature:25:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And v ← vector(-4, 6, 8)  features/transformations.feature:26:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then transform * v = vector(-8, 18, 32) [INFO] [stdout]  features/transformations.feature:27:4 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Multiplying by the inverse of a scaling matrix [INFO] [stdout]  features/transformations.feature:29:11 [INFO] [stdout]  - Given transform ← scaling(2, 3, 4)  features/transformations.feature:30:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And inv ← inverse(transform)  features/transformations.feature:31:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And v ← vector(-4, 6, 8)  features/transformations.feature:32:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then inv * v = vector(-2, 2, 2)  features/transformations.feature:33:4 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Reflection is scaling by a negative value [INFO] [stdout]  features/transformations.feature:35:11 [INFO] [stdout]  - Given transform ← scaling(-1, 1, 1)  features/transformations.feature:36:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(2, 3, 4)  features/transformations.feature:37:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then transform * p = point(-2, 3, 4)  features/transformations.feature:38:4 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Rotating a point around the x axis [INFO] [stdout]  features/transformations.feature:40:11 [INFO] [stdout]  - Given p ← point(0, 1, 0)  features/transformations.feature:41:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And half_quarter ← rotation_x(π / 4)  features/transformations.feature:42:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And full_quarter ← rotation_x(π / 2)  features/transformations.feature:43:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then half_quarter * p = point(0, √2/2, √2/2) [INFO] [stdout]  features/transformations.feature:44:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And full_quarter * p = point(0, 0, 1) features/transformations.feature:45:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The inverse of an x-rotation rotates in the opposite direction [INFO] [stdout]  features/transformations.feature:47:11 [INFO] [stdout]  - Given p ← point(0, 1, 0)  features/transformations.feature:48:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And half_quarter ← rotation_x(π / 4)  features/transformations.feature:49:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And inv ← inverse(half_quarter)  features/transformations.feature:50:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then inv * p = point(0, √2/2, -√2/2)  features/transformations.feature:51:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Rotating a point around the y axis [INFO] [stdout]  features/transformations.feature:53:11 [INFO] [stdout]  - Given p ← point(0, 0, 1)  features/transformations.feature:54:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And half_quarter ← rotation_y(π / 4)  features/transformations.feature:55:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And full_quarter ← rotation_y(π / 2)  features/transformations.feature:56:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then half_quarter * p = point(√2/2, 0, √2/2) [INFO] [stdout]  features/transformations.feature:57:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And full_quarter * p = point(1, 0, 0) features/transformations.feature:58:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Rotating a point around the z axis [INFO] [stdout]  features/transformations.feature:60:11 [INFO] [stdout]  - Given p ← point(0, 1, 0)  features/transformations.feature:61:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And half_quarter ← rotation_z(π / 4)  features/transformations.feature:62:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And full_quarter ← rotation_z(π / 2)  features/transformations.feature:63:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then half_quarter * p = point(-√2/2, √2/2, 0) [INFO] [stdout]  features/transformations.feature:64:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And full_quarter * p = point(-1, 0, 0) [INFO] [stdout]  features/transformations.feature:65:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A shearing transformation moves x in proportion to y [INFO] [stdout]  features/transformations.feature:67:11 [INFO] [stdout]  - Given transform ← shearing(1, 0, 0, 0, 0, 0) [INFO] [stdout]  features/transformations.feature:68:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(2, 3, 4)  features/transformations.feature:69:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then transform * p = point(5, 3, 4)  features/transformations.feature:70:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A shearing transformation moves x in proportion to z [INFO] [stdout]  features/transformations.feature:72:11 [INFO] [stdout]  - Given transform ← shearing(0, 1, 0, 0, 0, 0) [INFO] [stdout]  features/transformations.feature:73:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(2, 3, 4)  features/transformations.feature:74:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then transform * p = point(6, 3, 4)  features/transformations.feature:75:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A shearing transformation moves y in proportion to x [INFO] [stdout]  features/transformations.feature:77:11 [INFO] [stdout]  - Given transform ← shearing(0, 0, 1, 0, 0, 0) [INFO] [stdout]  features/transformations.feature:78:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(2, 3, 4)  features/transformations.feature:79:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then transform * p = point(2, 5, 4)  features/transformations.feature:80:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A shearing transformation moves y in proportion to z [INFO] [stdout]  features/transformations.feature:82:11 [INFO] [stdout]  - Given transform ← shearing(0, 0, 0, 1, 0, 0) [INFO] [stdout]  features/transformations.feature:83:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(2, 3, 4)  features/transformations.feature:84:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then transform * p = point(2, 7, 4)  features/transformations.feature:85:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A shearing transformation moves z in proportion to x [INFO] [stdout]  features/transformations.feature:87:11 [INFO] [stdout]  - Given transform ← shearing(0, 0, 0, 0, 1, 0) [INFO] [stdout]  features/transformations.feature:88:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(2, 3, 4)  features/transformations.feature:89:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then transform * p = point(2, 3, 6)  features/transformations.feature:90:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A shearing transformation moves z in proportion to y [INFO] [stdout]  features/transformations.feature:92:11 [INFO] [stdout]  - Given transform ← shearing(0, 0, 0, 0, 0, 1) [INFO] [stdout]  features/transformations.feature:93:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(2, 3, 4)  features/transformations.feature:94:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then transform * p = point(2, 3, 7)  features/transformations.feature:95:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Individual transformations are applied in sequence [INFO] [stdout]  features/transformations.feature:97:11 [INFO] [stdout]  - Given p ← point(1, 0, 1)  features/transformations.feature:98:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And A ← rotation_x(π / 2)  features/transformations.feature:99:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And B ← scaling(5, 5, 5)  features/transformations.feature:100:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And C ← translation(10, 5, 7)  features/transformations.feature:101:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When p2 ← A * p  features/transformations.feature:103:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then p2 = point(1, -1, 0)  features/transformations.feature:104:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When p3 ← B * p2  features/transformations.feature:106:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then p3 = point(5, -5, 0)  features/transformations.feature:107:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When p4 ← C * p3  features/transformations.feature:109:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then p4 = point(15, 0, 7)  features/transformations.feature:110:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Chained transformations must be applied in reverse order [INFO] [stdout]  features/transformations.feature:112:11 [INFO] [stdout]  - Given p ← point(1, 0, 1)  features/transformations.feature:113:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And A ← rotation_x(π / 2)  features/transformations.feature:114:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And B ← scaling(5, 5, 5)  features/transformations.feature:115:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And C ← translation(10, 5, 7)  features/transformations.feature:116:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When T ← C * B * A  features/transformations.feature:117:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then T * p = point(15, 0, 7)  features/transformations.feature:118:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The transformation matrix for the default orientation [INFO] [stdout]  features/transformations.feature:120:11 [INFO] [stdout]  - Given from ← point(0, 0, 0)  features/transformations.feature:121:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And to ← point(0, 0, -1)  features/transformations.feature:122:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And up ← vector(0, 1, 0)  features/transformations.feature:123:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When t ← view_transform(from, to, up) [INFO] [stdout]  features/transformations.feature:124:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then t = identity_matrix  features/transformations.feature:125:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A view transformation matrix looking in positive z direction [INFO] [stdout]  features/transformations.feature:127:11 [INFO] [stdout]  - Given from ← point(0, 0, 0)  features/transformations.feature:128:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And to ← point(0, 0, 1)  features/transformations.feature:129:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And up ← vector(0, 1, 0)  features/transformations.feature:130:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When t ← view_transform(from, to, up) [INFO] [stdout]  features/transformations.feature:131:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then t = scaling(-1, 1, -1)  features/transformations.feature:132:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The view transformation moves the world [INFO] [stdout]  features/transformations.feature:134:11 [INFO] [stdout]  - Given from ← point(0, 0, 8)  features/transformations.feature:135:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And to ← point(0, 0, 0)  features/transformations.feature:136:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And up ← vector(0, 1, 0)  features/transformations.feature:137:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When t ← view_transform(from, to, up) [INFO] [stdout]  features/transformations.feature:138:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then t = translation(0, 0, -8)  features/transformations.feature:139:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: An arbitrary view transformation [INFO] [stdout]  features/transformations.feature:141:11 [INFO] [stdout]  - Given from ← point(1, 3, 2)  features/transformations.feature:142:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And to ← point(4, -2, 8)  features/transformations.feature:143:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And up ← vector(1, 1, 0)  features/transformations.feature:144:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When t ← view_transform(from, to, up) [INFO] [stdout]  features/transformations.feature:145:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then t is the following 4x4 matrix:  features/transformations.feature:146:3 [INFO] [stdout]  | -0.50709 | 0.50709 | 0.67612 | -2.36643 | [INFO] [stdout] | 0.76772 | 0.60609 | 0.12122 | -2.82843 | [INFO] [stdout] | -0.35857 | 0.59761 | -0.71714 | 0.00000 | [INFO] [stdout] | 0.00000 | 0.00000 | 0.00000 | 1.00000 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: Triangles  features/triangles.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: Constructing a triangle  features/triangles.feature:3:11 [INFO] [stdout]  - Given p1 ← point(0, 1, 0)  features/triangles.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p2 ← point(-1, 0, 0)  features/triangles.feature:5:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p3 ← point(1, 0, 0)  features/triangles.feature:6:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t ← triangle(p1, p2, p3)  features/triangles.feature:7:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then t.p1 = p1  features/triangles.feature:8:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t.p2 = p2  features/triangles.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t.p3 = p3  features/triangles.feature:10:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t.e1 = vector(-1, -1, 0)  features/triangles.feature:11:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t.e2 = vector(1, -1, 0)  features/triangles.feature:12:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And t.normal = vector(0, 0, -1)  features/triangles.feature:13:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersecting a ray parallel to the triangle [INFO] [stdout]  features/triangles.feature:15:11 [INFO] [stdout]  - Given t ← triangle(point(0, 1, 0), point(-1, 0, 0), point(1, 0, 0)) [INFO] [stdout]  features/triangles.feature:16:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, -1, -2), vector(0, 1, 0)) [INFO] [stdout]  features/triangles.feature:17:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(t, r)  features/triangles.feature:18:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs is empty  features/triangles.feature:19:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray misses the p1-p3 edge  features/triangles.feature:21:11 [INFO] [stdout]  - Given t ← triangle(point(0, 1, 0), point(-1, 0, 0), point(1, 0, 0)) [INFO] [stdout]  features/triangles.feature:22:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(1, 1, -2), vector(0, 0, 1)) [INFO] [stdout]  features/triangles.feature:23:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(t, r)  features/triangles.feature:24:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs is empty  features/triangles.feature:25:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray misses the p1-p2 edge  features/triangles.feature:27:11 [INFO] [stdout]  - Given t ← triangle(point(0, 1, 0), point(-1, 0, 0), point(1, 0, 0)) [INFO] [stdout]  features/triangles.feature:28:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(-1, 1, -2), vector(0, 0, 1)) [INFO] [stdout]  features/triangles.feature:29:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(t, r)  features/triangles.feature:30:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs is empty  features/triangles.feature:31:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray misses the p2-p3 edge  features/triangles.feature:33:11 [INFO] [stdout]  - Given t ← triangle(point(0, 1, 0), point(-1, 0, 0), point(1, 0, 0)) [INFO] [stdout]  features/triangles.feature:34:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, -1, -2), vector(0, 0, 1)) [INFO] [stdout]  features/triangles.feature:35:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(t, r)  features/triangles.feature:36:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs is empty  features/triangles.feature:37:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A ray strikes a triangle  features/triangles.feature:39:11 [INFO] [stdout]  - Given t ← triangle(point(0, 1, 0), point(-1, 0, 0), point(1, 0, 0)) [INFO] [stdout]  features/triangles.feature:40:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0.5, -2), vector(0, 0, 1)) [INFO] [stdout]  features/triangles.feature:41:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← local_intersect(t, r)  features/triangles.feature:42:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 1  features/triangles.feature:43:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = 2  features/triangles.feature:44:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Finding the normal on a triangle  features/triangles.feature:46:11 [INFO] [stdout]  - Given t ← triangle(point(0, 1, 0), point(-1, 0, 0), point(1, 0, 0)) [INFO] [stdout]  features/triangles.feature:47:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When n1 ← local_normal_at(t, point(0, 0.5, 0)) [INFO] [stdout]  features/triangles.feature:48:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n2 ← local_normal_at(t, point(-0.5, 0.75, 0)) [INFO] [stdout]  features/triangles.feature:49:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n3 ← local_normal_at(t, point(0.5, 0.25, 0)) [INFO] [stdout]  features/triangles.feature:50:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then n1 = t.normal  features/triangles.feature:51:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n2 = t.normal  features/triangles.feature:52:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n3 = t.normal  features/triangles.feature:53:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: Tuples, Vectors, and Points  features/tuples.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: A tuple with w=1.0 is a point  features/tuples.feature:3:11 [INFO] [stdout]  - Given a ← tuple(4.3, -4.2, 3.1, 1.0)  features/tuples.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then a.x = 4.3  features/tuples.feature:5:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And a.y = -4.2  features/tuples.feature:6:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And a.z = 3.1  features/tuples.feature:7:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And a.w = 1.0  features/tuples.feature:8:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And a is a point  features/tuples.feature:9:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And a is not a vector  features/tuples.feature:10:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: A tuple with w=0 is a vector  features/tuples.feature:12:11 [INFO] [stdout]  - Given a ← tuple(4.3, -4.2, 3.1, 0.0)  features/tuples.feature:13:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then a.x = 4.3  features/tuples.feature:14:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And a.y = -4.2  features/tuples.feature:15:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And a.z = 3.1  features/tuples.feature:16:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And a.w = 0.0  features/tuples.feature:17:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And a is not a point  features/tuples.feature:18:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And a is a vector  features/tuples.feature:19:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: point() creates tuples with w=1  features/tuples.feature:21:11 [INFO] [stdout]  - Given p ← point(4, -4, 3)  features/tuples.feature:22:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then p = tuple(4, -4, 3, 1)  features/tuples.feature:23:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: vector() creates tuples with w=0  features/tuples.feature:25:11 [INFO] [stdout]  - Given v ← vector(4, -4, 3)  features/tuples.feature:26:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then v = tuple(4, -4, 3, 0)  features/tuples.feature:27:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Adding two tuples  features/tuples.feature:29:11 [INFO] [stdout]  - Given a1 ← tuple(3, -2, 5, 1)  features/tuples.feature:30:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And a2 ← tuple(-2, 3, 1, 0)  features/tuples.feature:31:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then a1 + a2 = tuple(1, 1, 6, 1)  features/tuples.feature:32:4 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Subtracting two points  features/tuples.feature:34:11 [INFO] [stdout]  - Given p1 ← point(3, 2, 1)  features/tuples.feature:35:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p2 ← point(5, 6, 7)  features/tuples.feature:36:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then p1 - p2 = vector(-2, -4, -6)  features/tuples.feature:37:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Subtracting a vector from a point  features/tuples.feature:39:11 [INFO] [stdout]  - Given p ← point(3, 2, 1)  features/tuples.feature:40:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And v ← vector(5, 6, 7)  features/tuples.feature:41:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then p - v = point(-2, -4, -6)  features/tuples.feature:42:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Subtracting two vectors  features/tuples.feature:44:11 [INFO] [stdout]  - Given v1 ← vector(3, 2, 1)  features/tuples.feature:45:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And v2 ← vector(5, 6, 7)  features/tuples.feature:46:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then v1 - v2 = vector(-2, -4, -6)  features/tuples.feature:47:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Subtracting a vector from the zero vector [INFO] [stdout]  features/tuples.feature:49:11 [INFO] [stdout]  - Given zero ← vector(0, 0, 0)  features/tuples.feature:50:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And v ← vector(1, -2, 3)  features/tuples.feature:51:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then zero - v = vector(-1, 2, -3)  features/tuples.feature:52:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Negating a tuple  features/tuples.feature:54:11 [INFO] [stdout]  - Given a ← tuple(1, -2, 3, -4)  features/tuples.feature:55:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then -a = tuple(-1, 2, -3, 4)  features/tuples.feature:56:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Multiplying a tuple by a scalar  features/tuples.feature:58:11 [INFO] [stdout]  - Given a ← tuple(1, -2, 3, -4)  features/tuples.feature:59:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then a * 3.5 = tuple(3.5, -7, 10.5, -14)  features/tuples.feature:60:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Multiplying a tuple by a fraction  features/tuples.feature:62:11 [INFO] [stdout]  - Given a ← tuple(1, -2, 3, -4)  features/tuples.feature:63:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then a * 0.5 = tuple(0.5, -1, 1.5, -2)  features/tuples.feature:64:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Dividing a tuple by a scalar  features/tuples.feature:66:11 [INFO] [stdout]  - Given a ← tuple(1, -2, 3, -4)  features/tuples.feature:67:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then a / 2 = tuple(0.5, -1, 1.5, -2)  features/tuples.feature:68:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Computing the magnitude of vector(1, 0, 0) [INFO] [stdout]  features/tuples.feature:70:11 [INFO] [stdout]  - Given v ← vector(1, 0, 0)  features/tuples.feature:71:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then magnitude(v) = 1  features/tuples.feature:72:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Computing the magnitude of vector(0, 1, 0) [INFO] [stdout]  features/tuples.feature:74:11 [INFO] [stdout]  - Given v ← vector(0, 1, 0)  features/tuples.feature:75:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then magnitude(v) = 1  features/tuples.feature:76:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Computing the magnitude of vector(0, 0, 1) [INFO] [stdout]  features/tuples.feature:78:11 [INFO] [stdout]  - Given v ← vector(0, 0, 1)  features/tuples.feature:79:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then magnitude(v) = 1  features/tuples.feature:80:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Computing the magnitude of vector(1, 2, 3) [INFO] [stdout]  features/tuples.feature:82:11 [INFO] [stdout]  - Given v ← vector(1, 2, 3)  features/tuples.feature:83:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then magnitude(v) = √14  features/tuples.feature:84:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Computing the magnitude of vector(-1, -2, -3) [INFO] [stdout]  features/tuples.feature:86:11 [INFO] [stdout]  - Given v ← vector(-1, -2, -3)  features/tuples.feature:87:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then magnitude(v) = √14  features/tuples.feature:88:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Normalizing vector(4, 0, 0) gives (1, 0, 0) [INFO] [stdout]  features/tuples.feature:90:11 [INFO] [stdout]  - Given v ← vector(4, 0, 0)  features/tuples.feature:91:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then normalize(v) = vector(1, 0, 0)  features/tuples.feature:92:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Normalizing vector(1, 2, 3)  features/tuples.feature:94:11 [INFO] [stdout]  - Given v ← vector(1, 2, 3)  features/tuples.feature:95:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then normalize(v) = approximately vector(0.26726, 0.53452, 0.80178) [INFO] [stdout]  features/tuples.feature:97:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The magnitude of a normalized vector  features/tuples.feature:99:11 [INFO] [stdout]  - Given v ← vector(1, 2, 3)  features/tuples.feature:100:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When norm ← normalize(v)  features/tuples.feature:101:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then magnitude(norm) = 1  features/tuples.feature:102:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The dot product of two tuples  features/tuples.feature:104:11 [INFO] [stdout]  - Given a ← vector(1, 2, 3)  features/tuples.feature:105:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And b ← vector(2, 3, 4)  features/tuples.feature:106:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then dot(a, b) = 20  features/tuples.feature:107:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The cross product of two vectors  features/tuples.feature:109:11 [INFO] [stdout]  - Given a ← vector(1, 2, 3)  features/tuples.feature:110:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And b ← vector(2, 3, 4)  features/tuples.feature:111:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then cross(a, b) = vector(-1, 2, -1)  features/tuples.feature:112:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And cross(b, a) = vector(1, -2, 1)  features/tuples.feature:113:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Colors are (red, green, blue) tuples  features/tuples.feature:115:11 [INFO] [stdout]  - Given c ← color(-0.5, 0.4, 1.7)  features/tuples.feature:116:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c.red = -0.5  features/tuples.feature:117:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c.green = 0.4  features/tuples.feature:118:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c.blue = 1.7  features/tuples.feature:119:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Adding colors  features/tuples.feature:121:11 [INFO] [stdout]  - Given c1 ← color(0.9, 0.6, 0.75)  features/tuples.feature:122:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c2 ← color(0.7, 0.1, 0.25)  features/tuples.feature:123:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c1 + c2 = color(1.6, 0.7, 1.0)  features/tuples.feature:124:4 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Subtracting colors  features/tuples.feature:126:11 [INFO] [stdout]  - Given c1 ← color(0.9, 0.6, 0.75)  features/tuples.feature:127:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c2 ← color(0.7, 0.1, 0.25)  features/tuples.feature:128:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c1 - c2 = color(0.2, 0.5, 0.5)  features/tuples.feature:129:4 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Multiplying a color by a scalar  features/tuples.feature:131:11 [INFO] [stdout]  - Given c ← color(0.2, 0.3, 0.4)  features/tuples.feature:132:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c * 2 = color(0.4, 0.6, 0.8)  features/tuples.feature:133:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Multiplying colors  features/tuples.feature:135:11 [INFO] [stdout]  - Given c1 ← color(1, 0.2, 0.4)  features/tuples.feature:136:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c2 ← color(0.9, 1, 0.1)  features/tuples.feature:137:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c1 * c2 = color(0.9, 0.2, 0.04)  features/tuples.feature:138:4 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Reflecting a vector approaching at 45° [INFO] [stdout]  features/tuples.feature:140:11 [INFO] [stdout]  - Given v ← vector(1, -1, 0)  features/tuples.feature:141:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n ← vector(0, 1, 0)  features/tuples.feature:142:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When r ← reflect(v, n)  features/tuples.feature:143:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then r = vector(1, 1, 0)  features/tuples.feature:144:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Reflecting a vector off a slanted surface [INFO] [stdout]  features/tuples.feature:146:11 [INFO] [stdout]  - Given v ← vector(0, -1, 0)  features/tuples.feature:147:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And n ← vector(√2/2, √2/2, 0)  features/tuples.feature:148:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When r ← reflect(v, n)  features/tuples.feature:149:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then r = vector(1, 0, 0)  features/tuples.feature:150:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] Feature: World  features/world.feature:1:1 [INFO] [stdout]  [INFO] [stdout]  Scenario: Creating a world  features/world.feature:3:11 [INFO] [stdout]  - Given w ← world()  features/world.feature:4:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then w contains no objects  features/world.feature:5:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And w has no light source  features/world.feature:6:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The default world  features/world.feature:8:11 [INFO] [stdout]  - Given light ← point_light(point(-10, 10, -10), color(1, 1, 1)) [INFO] [stdout]  features/world.feature:9:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s1 ← sphere() with:  features/world.feature:10:5 [INFO] [stdout]  | material.color | (0.8, 1.0, 0.6) | [INFO] [stdout] | material.diffuse | 0.7 | [INFO] [stdout] | material.specular | 0.2 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s2 ← sphere() with:  features/world.feature:14:5 [INFO] [stdout]  | | | [INFO] [stdout] | transform | scaling(0.5, 0.5, 0.5) | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When w ← default_world()  features/world.feature:16:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then w.light = light  features/world.feature:17:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And w contains s1  features/world.feature:18:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And w contains s2  features/world.feature:19:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Intersect a world with a ray  features/world.feature:21:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:22:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -5), vector(0, 0, 1))  features/world.feature:23:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When xs ← intersect_world(w, r)  features/world.feature:24:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then xs.count = 4  features/world.feature:25:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[0].t = 4  features/world.feature:26:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[1].t = 4.5  features/world.feature:27:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[2].t = 5.5  features/world.feature:28:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs[3].t = 6  features/world.feature:29:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Shading an intersection  features/world.feature:31:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:32:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -5), vector(0, 0, 1))  features/world.feature:33:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape ← the first object in w  features/world.feature:34:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i ← intersection(4, shape)  features/world.feature:35:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(i, r)  features/world.feature:36:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c ← shade_hit(w, comps)  features/world.feature:37:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c = color(0.38066, 0.47583, 0.2855)  features/world.feature:38:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: Shading an intersection from the inside features/world.feature:40:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:41:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And w.light ← point_light(point(0, 0.25, 0), color(1, 1, 1)) [INFO] [stdout]  features/world.feature:42:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, 0), vector(0, 0, 1))  features/world.feature:43:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape ← the second object in w  features/world.feature:44:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i ← intersection(0.5, shape)  features/world.feature:45:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(i, r)  features/world.feature:46:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c ← shade_hit(w, comps)  features/world.feature:47:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c = color(0.90498, 0.90498, 0.90498)  features/world.feature:48:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The color when a ray misses  features/world.feature:50:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:51:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -5), vector(0, 1, 0))  features/world.feature:52:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When c ← color_at(w, r)  features/world.feature:53:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c = color(0, 0, 0)  features/world.feature:54:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The color when a ray hits  features/world.feature:56:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:57:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -5), vector(0, 0, 1))  features/world.feature:58:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When c ← color_at(w, r)  features/world.feature:59:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c = color(0.38066, 0.47583, 0.2855)  features/world.feature:60:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The color with an intersection behind the ray [INFO] [stdout]  features/world.feature:62:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:63:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And outer ← the first object in w  features/world.feature:64:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And outer.material.ambient ← 1  features/world.feature:65:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And inner ← the second object in w  features/world.feature:66:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And inner.material.ambient ← 1  features/world.feature:67:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, 0.75), vector(0, 0, -1)) [INFO] [stdout]  features/world.feature:68:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When c ← color_at(w, r)  features/world.feature:69:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c = inner.material.color  features/world.feature:70:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: There is no shadow when nothing is collinear with point and light [INFO] [stdout]  features/world.feature:72:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:73:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(0, 10, 0)  features/world.feature:74:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then is_shadowed(w, p) is false  features/world.feature:75:4 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The shadow when an object is between the point and the light [INFO] [stdout]  features/world.feature:77:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:78:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(10, -10, 10)  features/world.feature:79:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then is_shadowed(w, p) is true  features/world.feature:80:4 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: There is no shadow when an object is behind the light [INFO] [stdout]  features/world.feature:82:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:83:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(-20, 20, -20)  features/world.feature:84:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then is_shadowed(w, p) is false  features/world.feature:85:4 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: There is no shadow when an object is behind the point [INFO] [stdout]  features/world.feature:87:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:88:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And p ← point(-2, 2, -2)  features/world.feature:89:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then is_shadowed(w, p) is false  features/world.feature:90:4 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: shade_hit() is given an intersection in shadow [INFO] [stdout]  features/world.feature:92:11 [INFO] [stdout]  - Given w ← world()  features/world.feature:93:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And w.light ← point_light(point(0, 0, -10), color(1, 1, 1)) [INFO] [stdout]  features/world.feature:94:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s1 ← sphere()  features/world.feature:95:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s1 is added to w  features/world.feature:96:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s2 ← sphere() with:  features/world.feature:97:5 [INFO] [stdout]  | | | [INFO] [stdout] | transform | translation(0, 0, 10) | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And s2 is added to w  features/world.feature:99:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, 5), vector(0, 0, 1))  features/world.feature:100:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i ← intersection(4, s2)  features/world.feature:101:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(i, r)  features/world.feature:102:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c ← shade_hit(w, comps)  features/world.feature:103:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c = color(0.1, 0.1, 0.1)  features/world.feature:104:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The reflected color for a nonreflective material [INFO] [stdout]  features/world.feature:106:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:107:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, 0), vector(0, 0, 1))  features/world.feature:108:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape ← the second object in w  features/world.feature:109:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape.material.ambient ← 1  features/world.feature:110:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i ← intersection(1, shape)  features/world.feature:111:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(i, r)  features/world.feature:112:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And color ← reflected_color(w, comps)  features/world.feature:113:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then color = color(0, 0, 0)  features/world.feature:114:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The reflected color for a reflective material [INFO] [stdout]  features/world.feature:116:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:117:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape ← plane() with:  features/world.feature:118:5 [INFO] [stdout]  | material.reflective | 0.5 | [INFO] [stdout] | transform | translation(0, -1, 0) | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape is added to w  features/world.feature:121:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -3), vector(0, -√2/2, √2/2)) [INFO] [stdout]  features/world.feature:122:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i ← intersection(√2, shape)  features/world.feature:123:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(i, r)  features/world.feature:124:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And color ← reflected_color(w, comps)  features/world.feature:125:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then color = color(0.19032, 0.2379, 0.14274)  features/world.feature:126:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: shade_hit() with a reflective material features/world.feature:128:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:129:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape ← plane() with:  features/world.feature:130:5 [INFO] [stdout]  | material.reflective | 0.5 | [INFO] [stdout] | transform | translation(0, -1, 0) | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape is added to w  features/world.feature:133:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -3), vector(0, -√2/2, √2/2)) [INFO] [stdout]  features/world.feature:134:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i ← intersection(√2, shape)  features/world.feature:135:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(i, r)  features/world.feature:136:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And color ← shade_hit(w, comps)  features/world.feature:137:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then color = color(0.87677, 0.92436, 0.82918)  features/world.feature:138:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: color_at() with mutually reflective surfaces [INFO] [stdout]  features/world.feature:140:11 [INFO] [stdout]  - Given w ← world()  features/world.feature:141:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And w.light ← point_light(point(0, 0, 0), color(1, 1, 1)) [INFO] [stdout]  features/world.feature:142:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And lower ← plane() with:  features/world.feature:143:5 [INFO] [stdout]  | material.reflective | 1 | [INFO] [stdout] | transform | translation(0, -1, 0) | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And lower is added to w  features/world.feature:146:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And upper ← plane() with:  features/world.feature:147:5 [INFO] [stdout]  | material.reflective | 1 | [INFO] [stdout] | transform | translation(0, 1, 0) | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And upper is added to w  features/world.feature:150:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, 0), vector(0, 1, 0))  features/world.feature:151:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then color_at(w, r) should terminate successfully [INFO] [stdout]  features/world.feature:152:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The reflected color at the maximum recursive depth [INFO] [stdout]  features/world.feature:154:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:155:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape ← plane() with:  features/world.feature:156:5 [INFO] [stdout]  | material.reflective | 0.5 | [INFO] [stdout] | transform | translation(0, -1, 0) | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape is added to w  features/world.feature:159:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -3), vector(0, -√2/2, √2/2)) [INFO] [stdout]  features/world.feature:160:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And i ← intersection(√2, shape)  features/world.feature:161:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(i, r)  features/world.feature:162:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And color ← reflected_color(w, comps, 0)  features/world.feature:163:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then color = color(0, 0, 0)  features/world.feature:164:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The refracted color with an opaque surface [INFO] [stdout]  features/world.feature:166:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:167:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape ← the first object in w  features/world.feature:168:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -5), vector(0, 0, 1))  features/world.feature:169:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(4:shape, 6:shape)  features/world.feature:170:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(xs[0], r, xs) [INFO] [stdout]  features/world.feature:171:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c ← refracted_color(w, comps, 5)  features/world.feature:172:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c = color(0, 0, 0)  features/world.feature:173:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The refracted color at the maximum recursive depth [INFO] [stdout]  features/world.feature:175:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:176:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape ← the first object in w  features/world.feature:177:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape has:  features/world.feature:178:5 [INFO] [stdout]  | material.transparency | 1.0 | [INFO] [stdout] | material.refractive_index | 1.5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -5), vector(0, 0, 1))  features/world.feature:181:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(4:shape, 6:shape)  features/world.feature:182:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(xs[0], r, xs) [INFO] [stdout]  features/world.feature:183:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c ← refracted_color(w, comps, 0)  features/world.feature:184:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c = color(0, 0, 0)  features/world.feature:185:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The refracted color under total internal reflection [INFO] [stdout]  features/world.feature:187:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:188:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape ← the first object in w  features/world.feature:189:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And shape has:  features/world.feature:190:5 [INFO] [stdout]  | material.transparency | 1.0 | [INFO] [stdout] | material.refractive_index | 1.5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, √2/2), vector(0, 1, 0)) [INFO] [stdout]  features/world.feature:193:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(-√2/2:shape, √2/2:shape) [INFO] [stdout]  features/world.feature:194:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(xs[1], r, xs) [INFO] [stdout]  features/world.feature:197:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c ← refracted_color(w, comps, 5)  features/world.feature:198:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c = color(0, 0, 0)  features/world.feature:199:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: The refracted color with a refracted ray [INFO] [stdout]  features/world.feature:201:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:202:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And A ← the first object in w  features/world.feature:203:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And A has:  features/world.feature:204:5 [INFO] [stdout]  | material.ambient | 1.0 | [INFO] [stdout] | material.pattern | test_pattern() | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And B ← the second object in w  features/world.feature:207:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And B has:  features/world.feature:208:5 [INFO] [stdout]  | material.transparency | 1.0 | [INFO] [stdout] | material.refractive_index | 1.5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, 0.1), vector(0, 1, 0)) features/world.feature:211:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(-0.9899:A, -0.4899:B, 0.4899:B, 0.9899:A) [INFO] [stdout]  features/world.feature:212:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(xs[2], r, xs) [INFO] [stdout]  features/world.feature:213:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And c ← refracted_color(w, comps, 5)  features/world.feature:214:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then c = color(0, 0.99888, 0.04725)  features/world.feature:215:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: shade_hit() with a transparent material [INFO] [stdout]  features/world.feature:217:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:218:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And floor ← plane() with:  features/world.feature:219:5 [INFO] [stdout]  | transform | translation(0, -1, 0) | [INFO] [stdout] | material.transparency | 0.5 | [INFO] [stdout] | material.refractive_index | 1.5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And floor is added to w  features/world.feature:223:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And ball ← sphere() with:  features/world.feature:224:5 [INFO] [stdout]  | material.color | (1, 0, 0) | [INFO] [stdout] | material.ambient | 0.5 | [INFO] [stdout] | transform | translation(0, -3.5, -0.5) | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And ball is added to w  features/world.feature:228:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -3), vector(0, -√2/2, √2/2)) [INFO] [stdout]  features/world.feature:229:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(√2:floor)  features/world.feature:230:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(xs[0], r, xs) [INFO] [stdout]  features/world.feature:231:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And color ← shade_hit(w, comps, 5)  features/world.feature:232:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then color = color(0.93642, 0.68642, 0.68642)  features/world.feature:233:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout]  Scenario: shade_hit() with a reflective, transparent material [INFO] [stdout]  features/world.feature:235:11 [INFO] [stdout]  - Given w ← default_world()  features/world.feature:236:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And r ← ray(point(0, 0, -3), vector(0, -√2/2, √2/2)) [INFO] [stdout]  features/world.feature:237:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And floor ← plane() with:  features/world.feature:238:5 [INFO] [stdout]  | transform | translation(0, -1, 0) | [INFO] [stdout] | material.reflective | 0.5 | [INFO] [stdout] | material.transparency | 0.5 | [INFO] [stdout] | material.refractive_index | 1.5 | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And floor is added to w  features/world.feature:243:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And ball ← sphere() with:  features/world.feature:244:5 [INFO] [stdout]  | material.color | (1, 0, 0) | [INFO] [stdout] | material.ambient | 0.5 | [INFO] [stdout] | transform | translation(0, -3.5, -0.5) | [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And ball is added to w  features/world.feature:248:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And xs ← intersections(√2:floor)  features/world.feature:249:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - When comps ← prepare_computations(xs[0], r, xs) [INFO] [stdout]  features/world.feature:250:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - And color ← shade_hit(w, comps, 5)  features/world.feature:251:5 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout]  - Then color = color(0.93391, 0.69643, 0.69243)  features/world.feature:252:3 [INFO] [stdout]  ⚡ Not yet implemented (skipped) [INFO] [stdout] [INFO] [stdout] 22 features [INFO] [stdout] 318 scenarios (318 skipped, 0 passed) [INFO] [stdout] 1637 steps (1637 skipped, 0 passed) [INFO] [stdout]  [INFO] running `"docker" "inspect" "0db4cc7d5fc449470fb197b3dcb636d1558e90cc066f71722840ecb976ec7e95"` [INFO] running `"docker" "rm" "-f" "0db4cc7d5fc449470fb197b3dcb636d1558e90cc066f71722840ecb976ec7e95"` [INFO] [stdout] 0db4cc7d5fc449470fb197b3dcb636d1558e90cc066f71722840ecb976ec7e95