From a3614b29a7686bba46cf1908722b2dbe8d71e528 Mon Sep 17 00:00:00 2001 From: Vitaly Slobodin Date: Sat, 24 Jan 2026 23:36:59 +0100 Subject: [PATCH 1/4] test: Add tree-sitter query snapshot-based testing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added a Rust-based integration test harness that runs quries directly through `tree‑sitter` and snapshots the captures using insta, mirroring the Jest snapshot review/accept flow. --- Cargo.lock | 276 +- Cargo.toml | 6 + tests/languages/ruby/debugger.rb | 101 + tests/languages/ruby/injections.rb | 15 + tests/languages/ruby/outline.rb | 250 ++ tests/languages/ruby/runnables.rb | 272 ++ tests/languages/ruby/snapshots/debugger.snap | 248 ++ .../languages/ruby/snapshots/injections.snap | 52 + tests/languages/ruby/snapshots/outline.snap | 1704 ++++++++++++ tests/languages/ruby/snapshots/runnables.snap | 2320 +++++++++++++++++ .../languages/ruby/snapshots/textobjects.snap | 68 + tests/languages/ruby/textobjects.rb | 24 + tests/ruby.rs | 66 + tests/support/mod.rs | 151 ++ 14 files changed, 5552 insertions(+), 1 deletion(-) create mode 100644 tests/languages/ruby/debugger.rb create mode 100644 tests/languages/ruby/injections.rb create mode 100644 tests/languages/ruby/outline.rb create mode 100644 tests/languages/ruby/runnables.rb create mode 100644 tests/languages/ruby/snapshots/debugger.snap create mode 100644 tests/languages/ruby/snapshots/injections.snap create mode 100644 tests/languages/ruby/snapshots/outline.snap create mode 100644 tests/languages/ruby/snapshots/runnables.snap create mode 100644 tests/languages/ruby/snapshots/textobjects.snap create mode 100644 tests/languages/ruby/textobjects.rb create mode 100644 tests/ruby.rs create mode 100644 tests/support/mod.rs diff --git a/Cargo.lock b/Cargo.lock index a0b13d6..3789bc2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,12 +47,34 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "cc" +version = "1.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583" +dependencies = [ + "find-msvc-tools", + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "console" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "windows-sys 0.59.0", +] + [[package]] name = "crc32fast" version = "1.4.2" @@ -73,12 +95,40 @@ dependencies = [ "syn", ] +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "find-msvc-tools" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" + [[package]] name = "flate2" version = "1.1.1" @@ -193,6 +243,18 @@ dependencies = [ "slab", ] +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + [[package]] name = "hashbrown" version = "0.15.3" @@ -364,6 +426,19 @@ dependencies = [ "serde", ] +[[package]] +name = "insta" +version = "1.46.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248b42847813a1550dafd15296fd9748c651d0c32194559dbc05d804d54b21e8" +dependencies = [ + "console", + "once_cell", + "serde", + "similar", + "tempfile", +] + [[package]] name = "itoa" version = "1.0.11" @@ -376,6 +451,18 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" +[[package]] +name = "libc" +version = "0.2.180" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + [[package]] name = "litemap" version = "0.7.5" @@ -455,6 +542,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "regex" version = "1.12.2" @@ -484,6 +577,19 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + [[package]] name = "ryu" version = "1.0.18" @@ -535,6 +641,7 @@ version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ + "indexmap", "itoa", "memchr", "ryu", @@ -542,6 +649,18 @@ dependencies = [ "serde_core", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" + [[package]] name = "slab" version = "0.4.9" @@ -572,6 +691,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520" + [[package]] name = "syn" version = "2.0.101" @@ -594,6 +719,19 @@ dependencies = [ "syn", ] +[[package]] +name = "tempfile" +version = "3.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + [[package]] name = "tinystr" version = "0.7.6" @@ -610,6 +748,35 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" +[[package]] +name = "tree-sitter" +version = "0.25.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78f873475d258561b06f1c595d93308a7ed124d9977cb26b148c2084a4a3cc87" +dependencies = [ + "cc", + "regex", + "regex-syntax", + "serde_json", + "streaming-iterator", + "tree-sitter-language", +] + +[[package]] +name = "tree-sitter-language" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae62f7eae5eb549c71b76658648b72cc6111f2d87d24a1e31fa907f4943e3ce" + +[[package]] +name = "tree-sitter-ruby" +version = "0.23.1" +source = "git+https://github.com/tree-sitter/tree-sitter-ruby.git?rev=71bd32fb7607035768799732addba884a37a6210#71bd32fb7607035768799732addba884a37a6210" +dependencies = [ + "cc", + "tree-sitter-language", +] + [[package]] name = "unicode-ident" version = "1.0.13" @@ -645,6 +812,15 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen 0.51.0", +] + [[package]] name = "wasm-encoder" version = "0.227.1" @@ -686,6 +862,94 @@ dependencies = [ "semver", ] +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "wit-bindgen" version = "0.41.0" @@ -696,6 +960,12 @@ dependencies = [ "wit-bindgen-rust-macro", ] +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + [[package]] name = "wit-bindgen-core" version = "0.41.0" @@ -830,16 +1100,20 @@ checksum = "0729d50b4ca0a7e28e590bbe32e3ca0194d97ef654961451a424c661a366fca0" dependencies = [ "serde", "serde_json", - "wit-bindgen", + "wit-bindgen 0.41.0", ] [[package]] name = "zed_ruby" version = "0.16.5" dependencies = [ + "insta", "regex", "serde", "serde_json", + "streaming-iterator", + "tree-sitter", + "tree-sitter-ruby", "zed_extension_api", ] diff --git a/Cargo.toml b/Cargo.toml index 10be112..0d93a47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,9 @@ regex = "1.11.1" serde_json = "1.0" serde = {version = "1.0", features = ["derive"]} zed_extension_api = "0.7.0" + +[dev-dependencies] +tree-sitter = "0.25" +tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "71bd32fb7607035768799732addba884a37a6210" } +insta = { version = "1.46", features = ["yaml"] } +streaming-iterator = "0.1" diff --git a/tests/languages/ruby/debugger.rb b/tests/languages/ruby/debugger.rb new file mode 100644 index 0000000..0e72123 --- /dev/null +++ b/tests/languages/ruby/debugger.rb @@ -0,0 +1,101 @@ +# Debugger fixtures for tree-sitter queries + +# Assignments +class Example + def process + user = User.new + email = user.email + result = calculate_sum(1, 2) + @total = result + end + + def calculate_sum(a, b) + sum = a + b + sum + end +end + +# Method parameters +class Calculator + def add(x, y) + x + y + end + + def multiply(a, b, c = 1) + a * b * c + end + + def process(*args, **kwargs) + args.sum + kwargs.values.sum + end +end + +# Instance variables +class User + def initialize(name) + @name = name + @created_at = Time.now + @active = true + end + + def update(email) + @email = email + @updated_at = Time.now + end +end + +# Scopes +global_var = "test" + +class ScopeExample + def method_scope + local_var = 1 + another_var = 2 + + if local_var > 0 + scoped_var = 3 + end + end +end + +# Complex scenario +class ComplexExample + def process_data(input, options = {}) + @input = input + result = transform(input) + output = result.map { |item| item.value } + logger.info(output) + @processed = true + output + end + + def transform(data) + temp = data.dup + temp.filter { |x| x > 0 } + end +end + +# Call arguments +class ArgumentCalls + def audit(user, value) + log(user.name) + log(fetch()) + log(value) + end + + def fetch + "ok" + end + + def log(message) + message + end +end + +# Assignment calls +class AssignmentCalls + def update(user) + user.email = "test@example.com" + user.profile.name = "Tester" + end +end diff --git a/tests/languages/ruby/injections.rb b/tests/languages/ruby/injections.rb new file mode 100644 index 0000000..aec26dc --- /dev/null +++ b/tests/languages/ruby/injections.rb @@ -0,0 +1,15 @@ +# Inline RBS examples +#: (String) -> void +# @rbs (Integer) -> String +# | arg: String +# | (Integer) -> String + +def example(name) + name +end + +pattern = /[a-z]+/i + +sql = <<~SQL + SELECT * FROM users +SQL diff --git a/tests/languages/ruby/outline.rb b/tests/languages/ruby/outline.rb new file mode 100644 index 0000000..92a33bb --- /dev/null +++ b/tests/languages/ruby/outline.rb @@ -0,0 +1,250 @@ +# Outline fixtures for classes, modules, methods, tasks, and tests + +API_VERSION = "v1" + +class User + VERSION = "1.0" + + include Comparable + include Foo::Bar + include Baz + attr_reader :name, :email + alias_method "login", "sign_in" + + private + self.private + + def initialize(name) + @name = name + end + + private def secret + # hidden + end + + def public_method + # visible + end + + def self.build + new("default") + end + + private_class_method def self.build_private + new("private") + end + + class << self + def singleton_block_method + # singleton class method + end + end +end + +module Billing + include Payments + include Payments::Gateway + alias_method :charge, :bill + + private + self.private +end + +private def root_private + # root private +end + +def root_public + # root public +end + +def self.root_singleton + # root singleton +end + +# Root test methods + +describe "root describe" do +end + +context "root context" do +end + +test "root test" do +end + +it "root it" do +end + +its "root its" do +end + +specify "root specify" do +end + +example "root example" do +end + +feature "root feature" do +end + +scenario "root scenario" do +end + +shared_examples "root shared_examples" do +end + +fdescribe "root fdescribe" do +end + +fcontext "root fcontext" do +end + +fit "root fit" do +end + +fexample "root fexample" do +end + +focus "root focus" do +end + +xdescribe "root xdescribe" do +end + +xcontext "root xcontext" do +end + +xit "root xit" do +end + +xexample "root xexample" do +end + +xspecify "root xspecify" do +end + +skip "root skip" do +end + +pending "root pending" do +end + +it_behaves_like "root it_behaves_like" + +it_should_behave_like "root it_should_behave_like" + +include_context "root include_context" + +include_examples "root include_examples" + +# Nested test methods and one-liners + +describe "outer" do + context "inner" do + it "nested it" do + end + + specify "nested specify" do + end + + example "nested example" do + end + + feature "nested feature" do + end + + scenario "nested scenario" do + end + + shared_examples "nested shared_examples" do + end + + fdescribe "nested fdescribe" do + end + + fcontext "nested fcontext" do + end + + fit "nested fit" do + end + + fexample "nested fexample" do + end + + focus "nested focus" do + end + + xdescribe "nested xdescribe" do + end + + xcontext "nested xcontext" do + end + + xit "nested xit" do + end + + xexample "nested xexample" do + end + + xspecify "nested xspecify" do + end + + skip "nested skip" do + end + + pending "nested pending" do + end + + it_behaves_like "nested it_behaves_like" + + it_should_behave_like "nested it_should_behave_like" + + include_context "nested include_context" + + include_examples "nested include_examples" + + it { is_expected.to be_truthy } + it { is_expected.not_to be_nil } + its { is_expected.to be_empty } + specify { is_expected.to be_truthy } + example { is_expected.to be_truthy } + fit { is_expected.to be_truthy } + fexample { is_expected.to be_truthy } + focus { is_expected.to be_truthy } + xit { is_expected.to be_truthy } + xexample { is_expected.to be_truthy } + xspecify { is_expected.to be_truthy } + skip { is_expected.to be_truthy } + pending { is_expected.to be_truthy } + end +end + +# Rake namespaces and tasks + +namespace :db do + namespace :migrate do + task :up do + # migrate + end + end +end + +task :version do + # version +end + +task default: :test do + # default +end + +# Schema.rb style + +ActiveRecord::Schema.define(version: 2024_01_01) do + create_table "users" + create_enum "status" + create_schema "audit" + create_virtual_table "search" + enable_extension "pgcrypto" + add_foreign_key "orders", "users" +end diff --git a/tests/languages/ruby/runnables.rb b/tests/languages/ruby/runnables.rb new file mode 100644 index 0000000..a026dda --- /dev/null +++ b/tests/languages/ruby/runnables.rb @@ -0,0 +1,272 @@ +# Runnables fixtures for tree-sitter queries + +require "minitest/autorun" +require "test_helper" + +# RSpec fixtures + +shared_examples "a valid user" do + it "has an email" do + # test + end +end + +describe "User authentication" do + it "validates email format" do + expect(user.email).to match(/email/) + end + + context "with invalid credentials" do + it "returns an error" do + # test implementation + end + end + + context "with valid credentials" do + it "authenticates successfully" do + # test implementation + end + end +end + +describe "Billing system" do + context "with subscription" do + context "monthly plan" do + it "charges correctly" do + # test + end + + it "renews automatically" do + # test + end + end + + context "yearly plan" do + it "applies discount" do + # test + end + end + end + + context "without subscription" do + it "uses free tier" do + # test + end + end +end + +describe "Payment processing" do + fdescribe "credit card payment" do + it "processes successfully" do + # test + end + + fit "validates card number" do + # focused test + end + end + + describe "bank transfer" do + fcontext "with valid account" do + it "transfers funds" do + # test + end + end + end +end + +describe "Admin" do + it_behaves_like "a valid user" + + it "has admin privileges" do + # test + end +end + +describe "Customer" do + include_examples "a valid user" + + it "can place orders" do + # test + end +end + +describe "Guest" do + include_context "guest session" + + it "has limited access" do + # test + end +end + +describe UserService do + it "processes requests" do + # test + end +end + +describe API::V1::UsersController do + it "returns user list" do + # test + end +end + +describe SomeConstant do + it "has correct value" do + # test + end +end + +describe :user_service do + it :creates_user do + # test + end + + context :with_validation do + it :validates_email do + # test + end + end +end + +describe 123 do + it "handles numeric names" do + # test + end +end + +feature "Checkout flow" do + scenario "guest can buy" do + specify "shows tax breakdown" do + # test + end + + example "calculates totals" do + # test + end + end +end + +fexample "focused example" do + # test +end + +focus "explicit focus" do + # test +end + +describe "Shared behavior" do + it_should_behave_like "a purchasable item" +end + +describe User do + subject { User.new(email: "test@example.com") } + + it { is_expected.to be_valid } + it { is_expected.to respond_to(:email) } + its(:email) { is_expected.to include("@") } + + describe "validations" do + it { is_expected.to validate_presence_of(:email) } + end +end + +describe "One-liners extra" do + specify { expect(true).to be(true) } + example { expect(1).to eq(1) } + fit { expect(2).to eq(2) } + fexample { expect(3).to eq(3) } + focus { expect(4).to eq(4) } + its { is_expected.to be_nil } +end + +# Minitest fixtures + +class UserTest < Minitest::Test + def test_creates_user + # test + end + + def test_validates_email + # test + end + + def test_saves_to_database + # test + end +end + +class ProductTest < Minitest::Test + test "creates product" do + # test + end + + test "validates price" do + # test + end + + test "calculates discount" do + # test + end +end + +class UsersIntegrationTest < ActionDispatch::IntegrationTest + def test_user_signup_flow + # test + end +end + +class UserSystemTest < ApplicationSystemTestCase + def test_user_can_login + # test + end +end + +class AdminTest < ActiveSupport::TestCase + def test_admin_permissions + # test + end +end + +class SystemHealthTest < ::SystemTestCase + def test_system_health + # test + end +end + +class QuickCheckTest < ::TLDR + def test_quick_checks + # test + end +end + +class Admin::UserTest < ActiveSupport::TestCase + def test_scoped_class_name + # test + end +end + +# Edge cases + +describe "Edge cases" do + it "handles empty blocks" do + end + + it "handles special characters !@#$%^&*()" do + # test + end + + it "handles multiline + string names" do + # test + end + + it do + # one-liner with empty name block + end +end + +class EmptyTest < Minitest::Test + def test_empty + end +end diff --git a/tests/languages/ruby/snapshots/debugger.snap b/tests/languages/ruby/snapshots/debugger.snap new file mode 100644 index 0000000..27fe92b --- /dev/null +++ b/tests/languages/ruby/snapshots/debugger.snap @@ -0,0 +1,248 @@ +--- +source: tests/ruby.rs +expression: captures +--- +- name: debug-scope + line: 1 + column: 1 + text: "# Debugger fixtures for tree-sitter queries\n\n# Assignments\nclass Example\n def process\n user = User.new\n email = user.email\n result = calculate_sum(1, 2)\n @total = result\n end\n\n def calculate_sum(a, b)\n sum = a + b\n sum\n end\nend\n\n# Method parameters\nclass Calculator\n def add(x, y)\n x + y\n end\n\n def multiply(a, b, c = 1)\n a * b * c\n end\n\n def process(*args, **kwargs)\n args.sum + kwargs.values.sum\n end\nend\n\n# Instance variables\nclass User\n def initialize(name)\n @name = name\n @created_at = Time.now\n @active = true\n end\n\n def update(email)\n @email = email\n @updated_at = Time.now\n end\nend\n\n# Scopes\nglobal_var = \"test\"\n\nclass ScopeExample\n def method_scope\n local_var = 1\n another_var = 2\n\n if local_var > 0\n scoped_var = 3\n end\n end\nend\n\n# Complex scenario\nclass ComplexExample\n def process_data(input, options = {})\n @input = input\n result = transform(input)\n output = result.map { |item| item.value }\n logger.info(output)\n @processed = true\n output\n end\n\n def transform(data)\n temp = data.dup\n temp.filter { |x| x > 0 }\n end\nend\n\n# Call arguments\nclass ArgumentCalls\n def audit(user, value)\n log(user.name)\n log(fetch())\n log(value)\n end\n\n def fetch\n \"ok\"\n end\n\n def log(message)\n message\n end\nend\n\n# Assignment calls\nclass AssignmentCalls\n def update(user)\n user.email = \"test@example.com\"\n user.profile.name = \"Tester\"\n end\nend\n" +- name: debug-scope + line: 5 + column: 3 + text: "def process\n user = User.new\n email = user.email\n result = calculate_sum(1, 2)\n @total = result\n end\n\n def calculate_sum(a, b)\n sum = a + b\n sum\n end" +- name: debug-scope + line: 6 + column: 5 + text: "user = User.new\n email = user.email\n result = calculate_sum(1, 2)\n @total = result" +- name: debug-variable + line: 6 + column: 5 + text: user +- name: debug-variable + line: 7 + column: 5 + text: email +- name: debug-variable + line: 8 + column: 5 + text: result +- name: debug-variable + line: 9 + column: 5 + text: "@total" +- name: debug-variable + line: 12 + column: 20 + text: "(a, b)" +- name: debug-scope + line: 13 + column: 5 + text: "sum = a + b\n sum" +- name: debug-variable + line: 13 + column: 5 + text: sum +- name: debug-scope + line: 20 + column: 3 + text: "def add(x, y)\n x + y\n end\n\n def multiply(a, b, c = 1)\n a * b * c\n end\n\n def process(*args, **kwargs)\n args.sum + kwargs.values.sum\n end" +- name: debug-variable + line: 20 + column: 10 + text: "(x, y)" +- name: debug-scope + line: 21 + column: 5 + text: x + y +- name: debug-variable + line: 24 + column: 15 + text: "(a, b, c = 1)" +- name: debug-scope + line: 25 + column: 5 + text: a * b * c +- name: debug-variable + line: 28 + column: 14 + text: "(*args, **kwargs)" +- name: debug-scope + line: 29 + column: 5 + text: args.sum + kwargs.values.sum +- name: debug-scope + line: 35 + column: 3 + text: "def initialize(name)\n @name = name\n @created_at = Time.now\n @active = true\n end\n\n def update(email)\n @email = email\n @updated_at = Time.now\n end" +- name: debug-variable + line: 35 + column: 17 + text: (name) +- name: debug-scope + line: 36 + column: 5 + text: "@name = name\n @created_at = Time.now\n @active = true" +- name: debug-variable + line: 36 + column: 5 + text: "@name" +- name: debug-variable + line: 37 + column: 5 + text: "@created_at" +- name: debug-variable + line: 38 + column: 5 + text: "@active" +- name: debug-variable + line: 41 + column: 13 + text: (email) +- name: debug-scope + line: 42 + column: 5 + text: "@email = email\n @updated_at = Time.now" +- name: debug-variable + line: 42 + column: 5 + text: "@email" +- name: debug-variable + line: 43 + column: 5 + text: "@updated_at" +- name: debug-variable + line: 48 + column: 1 + text: global_var +- name: debug-scope + line: 51 + column: 3 + text: "def method_scope\n local_var = 1\n another_var = 2\n\n if local_var > 0\n scoped_var = 3\n end\n end" +- name: debug-scope + line: 52 + column: 5 + text: "local_var = 1\n another_var = 2\n\n if local_var > 0\n scoped_var = 3\n end" +- name: debug-variable + line: 52 + column: 5 + text: local_var +- name: debug-variable + line: 53 + column: 5 + text: another_var +- name: debug-variable + line: 56 + column: 7 + text: scoped_var +- name: debug-scope + line: 63 + column: 3 + text: "def process_data(input, options = {})\n @input = input\n result = transform(input)\n output = result.map { |item| item.value }\n logger.info(output)\n @processed = true\n output\n end\n\n def transform(data)\n temp = data.dup\n temp.filter { |x| x > 0 }\n end" +- name: debug-variable + line: 63 + column: 19 + text: "(input, options = {})" +- name: debug-scope + line: 64 + column: 5 + text: "@input = input\n result = transform(input)\n output = result.map { |item| item.value }\n logger.info(output)\n @processed = true\n output" +- name: debug-variable + line: 64 + column: 5 + text: "@input" +- name: debug-variable + line: 65 + column: 5 + text: result +- name: debug-variable + line: 65 + column: 24 + text: input +- name: debug-variable + line: 66 + column: 5 + text: output +- name: debug-variable + line: 67 + column: 17 + text: output +- name: debug-variable + line: 68 + column: 5 + text: "@processed" +- name: debug-variable + line: 72 + column: 16 + text: (data) +- name: debug-scope + line: 73 + column: 5 + text: "temp = data.dup\n temp.filter { |x| x > 0 }" +- name: debug-variable + line: 73 + column: 5 + text: temp +- name: debug-scope + line: 80 + column: 3 + text: "def audit(user, value)\n log(user.name)\n log(fetch())\n log(value)\n end\n\n def fetch\n \"ok\"\n end\n\n def log(message)\n message\n end" +- name: debug-variable + line: 80 + column: 12 + text: "(user, value)" +- name: debug-scope + line: 81 + column: 5 + text: "log(user.name)\n log(fetch())\n log(value)" +- name: debug-variable + line: 81 + column: 9 + text: user +- name: debug-variable + line: 81 + column: 14 + text: name +- name: debug-variable + line: 82 + column: 9 + text: fetch +- name: debug-variable + line: 83 + column: 9 + text: value +- name: debug-scope + line: 87 + column: 5 + text: "\"ok\"" +- name: debug-variable + line: 90 + column: 10 + text: (message) +- name: debug-scope + line: 91 + column: 5 + text: message +- name: debug-scope + line: 97 + column: 3 + text: "def update(user)\n user.email = \"test@example.com\"\n user.profile.name = \"Tester\"\n end" +- name: debug-variable + line: 97 + column: 13 + text: (user) +- name: debug-scope + line: 98 + column: 5 + text: "user.email = \"test@example.com\"\n user.profile.name = \"Tester\"" +- name: debug-variable + line: 98 + column: 5 + text: user +- name: debug-variable + line: 98 + column: 10 + text: email +- name: debug-variable + line: 99 + column: 18 + text: name diff --git a/tests/languages/ruby/snapshots/injections.snap b/tests/languages/ruby/snapshots/injections.snap new file mode 100644 index 0000000..242aecc --- /dev/null +++ b/tests/languages/ruby/snapshots/injections.snap @@ -0,0 +1,52 @@ +--- +source: tests/ruby.rs +expression: captures +--- +- name: content + line: 1 + column: 1 + text: "# Inline RBS examples" +- name: content + line: 2 + column: 1 + text: "#: (String) -> void" +- name: content + line: 2 + column: 1 + text: "#: (String) -> void" +- name: content + line: 3 + column: 1 + text: "# @rbs (Integer) -> String" +- name: content + line: 3 + column: 1 + text: "# @rbs (Integer) -> String" +- name: content + line: 4 + column: 1 + text: "# | arg: String" +- name: content + line: 4 + column: 1 + text: "# | arg: String" +- name: content + line: 5 + column: 1 + text: "# | (Integer) -> String" +- name: content + line: 5 + column: 1 + text: "# | (Integer) -> String" +- name: content + line: 11 + column: 12 + text: "[a-z]+" +- name: content + line: 13 + column: 13 + text: "\n SELECT * FROM users\n" +- name: language + line: 15 + column: 1 + text: SQL diff --git a/tests/languages/ruby/snapshots/outline.snap b/tests/languages/ruby/snapshots/outline.snap new file mode 100644 index 0000000..c7d6039 --- /dev/null +++ b/tests/languages/ruby/snapshots/outline.snap @@ -0,0 +1,1704 @@ +--- +source: tests/ruby.rs +expression: captures +--- +- name: item + line: 3 + column: 1 + text: "API_VERSION = \"v1\"" +- name: name + line: 3 + column: 1 + text: API_VERSION +- name: item + line: 5 + column: 1 + text: "class User\n VERSION = \"1.0\"\n\n include Comparable\n include Foo::Bar\n include Baz\n attr_reader :name, :email\n alias_method \"login\", \"sign_in\"\n\n private\n self.private\n\n def initialize(name)\n @name = name\n end\n\n private def secret\n # hidden\n end\n\n def public_method\n # visible\n end\n\n def self.build\n new(\"default\")\n end\n\n private_class_method def self.build_private\n new(\"private\")\n end\n\n class << self\n def singleton_block_method\n # singleton class method\n end\n end\nend" +- name: context + line: 5 + column: 1 + text: class +- name: name + line: 5 + column: 7 + text: User +- name: item + line: 6 + column: 3 + text: "VERSION = \"1.0\"" +- name: name + line: 6 + column: 3 + text: VERSION +- name: item + line: 8 + column: 3 + text: include Comparable +- name: name + line: 8 + column: 3 + text: include +- name: name + line: 8 + column: 11 + text: Comparable +- name: item + line: 9 + column: 3 + text: "include Foo::Bar" +- name: name + line: 9 + column: 3 + text: include +- name: name + line: 9 + column: 11 + text: "Foo::Bar" +- name: item + line: 10 + column: 3 + text: include Baz +- name: name + line: 10 + column: 3 + text: include +- name: name + line: 10 + column: 11 + text: Baz +- name: item + line: 11 + column: 3 + text: "attr_reader :name, :email" +- name: name + line: 11 + column: 3 + text: attr_reader +- name: name + line: 11 + column: 15 + text: ":name" +- name: context + line: 11 + column: 20 + text: "," +- name: name + line: 11 + column: 22 + text: ":email" +- name: item + line: 12 + column: 3 + text: "alias_method \"login\", \"sign_in\"" +- name: name + line: 12 + column: 3 + text: alias_method +- name: name + line: 12 + column: 16 + text: "\"login\"" +- name: context + line: 12 + column: 23 + text: "," +- name: name + line: 12 + column: 25 + text: "\"sign_in\"" +- name: name + line: 14 + column: 3 + text: private +- name: item + line: 14 + column: 3 + text: private +- name: item + line: 15 + column: 3 + text: self.private +- name: name + line: 15 + column: 8 + text: private +- name: item + line: 17 + column: 3 + text: "def initialize(name)\n @name = name\n end" +- name: context + line: 17 + column: 3 + text: def +- name: name + line: 17 + column: 7 + text: initialize +- name: item + line: 21 + column: 3 + text: "private def secret\n # hidden\n end" +- name: context + line: 21 + column: 3 + text: private +- name: context + line: 21 + column: 11 + text: def +- name: name + line: 21 + column: 15 + text: secret +- name: item + line: 25 + column: 3 + text: "def public_method\n # visible\n end" +- name: context + line: 25 + column: 3 + text: def +- name: name + line: 25 + column: 7 + text: public_method +- name: item + line: 29 + column: 3 + text: "def self.build\n new(\"default\")\n end" +- name: context + line: 29 + column: 3 + text: def +- name: context + line: 29 + column: 7 + text: self +- name: context + line: 29 + column: 11 + text: "." +- name: name + line: 29 + column: 12 + text: build +- name: item + line: 33 + column: 3 + text: "private_class_method def self.build_private\n new(\"private\")\n end" +- name: context + line: 33 + column: 3 + text: private_class_method +- name: item + line: 33 + column: 24 + text: "def self.build_private\n new(\"private\")\n end" +- name: context + line: 33 + column: 24 + text: def +- name: context + line: 33 + column: 28 + text: self +- name: context + line: 33 + column: 32 + text: "." +- name: name + line: 33 + column: 33 + text: build_private +- name: item + line: 37 + column: 3 + text: "class << self\n def singleton_block_method\n # singleton class method\n end\n end" +- name: context + line: 37 + column: 3 + text: class +- name: context + line: 37 + column: 9 + text: "<<" +- name: context + line: 37 + column: 12 + text: self +- name: item + line: 38 + column: 5 + text: "def singleton_block_method\n # singleton class method\n end" +- name: context + line: 38 + column: 5 + text: def +- name: name + line: 38 + column: 9 + text: singleton_block_method +- name: item + line: 44 + column: 1 + text: "module Billing\n include Payments\n include Payments::Gateway\n alias_method :charge, :bill\n\n private\n self.private\nend" +- name: context + line: 44 + column: 1 + text: module +- name: name + line: 44 + column: 8 + text: Billing +- name: item + line: 45 + column: 3 + text: include Payments +- name: name + line: 45 + column: 3 + text: include +- name: name + line: 45 + column: 11 + text: Payments +- name: item + line: 46 + column: 3 + text: "include Payments::Gateway" +- name: name + line: 46 + column: 3 + text: include +- name: name + line: 46 + column: 11 + text: "Payments::Gateway" +- name: item + line: 47 + column: 3 + text: "alias_method :charge, :bill" +- name: name + line: 47 + column: 3 + text: alias_method +- name: name + line: 47 + column: 16 + text: ":charge" +- name: context + line: 47 + column: 23 + text: "," +- name: name + line: 47 + column: 25 + text: ":bill" +- name: name + line: 49 + column: 3 + text: private +- name: item + line: 49 + column: 3 + text: private +- name: item + line: 50 + column: 3 + text: self.private +- name: name + line: 50 + column: 8 + text: private +- name: item + line: 53 + column: 1 + text: "private def root_private\n # root private\nend" +- name: context + line: 53 + column: 1 + text: private +- name: context + line: 53 + column: 9 + text: def +- name: name + line: 53 + column: 13 + text: root_private +- name: item + line: 57 + column: 1 + text: "def root_public\n # root public\nend" +- name: context + line: 57 + column: 1 + text: def +- name: name + line: 57 + column: 5 + text: root_public +- name: item + line: 61 + column: 1 + text: "def self.root_singleton\n # root singleton\nend" +- name: context + line: 61 + column: 1 + text: def +- name: context + line: 61 + column: 5 + text: self +- name: context + line: 61 + column: 9 + text: "." +- name: name + line: 61 + column: 10 + text: root_singleton +- name: item + line: 67 + column: 1 + text: "describe \"root describe\" do\nend" +- name: _run + line: 67 + column: 1 + text: describe +- name: name + line: 67 + column: 1 + text: describe +- name: name + line: 67 + column: 10 + text: "\"root describe\"" +- name: item + line: 70 + column: 1 + text: "context \"root context\" do\nend" +- name: _run + line: 70 + column: 1 + text: context +- name: name + line: 70 + column: 1 + text: context +- name: name + line: 70 + column: 9 + text: "\"root context\"" +- name: item + line: 73 + column: 1 + text: "test \"root test\" do\nend" +- name: _run + line: 73 + column: 1 + text: test +- name: name + line: 73 + column: 1 + text: test +- name: name + line: 73 + column: 6 + text: "\"root test\"" +- name: item + line: 76 + column: 1 + text: "it \"root it\" do\nend" +- name: _run + line: 76 + column: 1 + text: it +- name: name + line: 76 + column: 1 + text: it +- name: name + line: 76 + column: 4 + text: "\"root it\"" +- name: item + line: 79 + column: 1 + text: "its \"root its\" do\nend" +- name: _run + line: 79 + column: 1 + text: its +- name: name + line: 79 + column: 1 + text: its +- name: name + line: 79 + column: 5 + text: "\"root its\"" +- name: item + line: 82 + column: 1 + text: "specify \"root specify\" do\nend" +- name: _run + line: 82 + column: 1 + text: specify +- name: name + line: 82 + column: 1 + text: specify +- name: name + line: 82 + column: 9 + text: "\"root specify\"" +- name: item + line: 85 + column: 1 + text: "example \"root example\" do\nend" +- name: _run + line: 85 + column: 1 + text: example +- name: name + line: 85 + column: 1 + text: example +- name: name + line: 85 + column: 9 + text: "\"root example\"" +- name: item + line: 88 + column: 1 + text: "feature \"root feature\" do\nend" +- name: _run + line: 88 + column: 1 + text: feature +- name: name + line: 88 + column: 1 + text: feature +- name: name + line: 88 + column: 9 + text: "\"root feature\"" +- name: item + line: 91 + column: 1 + text: "scenario \"root scenario\" do\nend" +- name: _run + line: 91 + column: 1 + text: scenario +- name: name + line: 91 + column: 1 + text: scenario +- name: name + line: 91 + column: 10 + text: "\"root scenario\"" +- name: item + line: 94 + column: 1 + text: "shared_examples \"root shared_examples\" do\nend" +- name: _run + line: 94 + column: 1 + text: shared_examples +- name: name + line: 94 + column: 1 + text: shared_examples +- name: name + line: 94 + column: 17 + text: "\"root shared_examples\"" +- name: item + line: 97 + column: 1 + text: "fdescribe \"root fdescribe\" do\nend" +- name: _run + line: 97 + column: 1 + text: fdescribe +- name: name + line: 97 + column: 1 + text: fdescribe +- name: name + line: 97 + column: 11 + text: "\"root fdescribe\"" +- name: item + line: 100 + column: 1 + text: "fcontext \"root fcontext\" do\nend" +- name: _run + line: 100 + column: 1 + text: fcontext +- name: name + line: 100 + column: 1 + text: fcontext +- name: name + line: 100 + column: 10 + text: "\"root fcontext\"" +- name: item + line: 103 + column: 1 + text: "fit \"root fit\" do\nend" +- name: _run + line: 103 + column: 1 + text: fit +- name: name + line: 103 + column: 1 + text: fit +- name: name + line: 103 + column: 5 + text: "\"root fit\"" +- name: item + line: 106 + column: 1 + text: "fexample \"root fexample\" do\nend" +- name: _run + line: 106 + column: 1 + text: fexample +- name: name + line: 106 + column: 1 + text: fexample +- name: name + line: 106 + column: 10 + text: "\"root fexample\"" +- name: item + line: 109 + column: 1 + text: "focus \"root focus\" do\nend" +- name: _run + line: 109 + column: 1 + text: focus +- name: name + line: 109 + column: 1 + text: focus +- name: name + line: 109 + column: 7 + text: "\"root focus\"" +- name: item + line: 112 + column: 1 + text: "xdescribe \"root xdescribe\" do\nend" +- name: _run + line: 112 + column: 1 + text: xdescribe +- name: name + line: 112 + column: 1 + text: xdescribe +- name: name + line: 112 + column: 11 + text: "\"root xdescribe\"" +- name: item + line: 115 + column: 1 + text: "xcontext \"root xcontext\" do\nend" +- name: _run + line: 115 + column: 1 + text: xcontext +- name: name + line: 115 + column: 1 + text: xcontext +- name: name + line: 115 + column: 10 + text: "\"root xcontext\"" +- name: item + line: 118 + column: 1 + text: "xit \"root xit\" do\nend" +- name: _run + line: 118 + column: 1 + text: xit +- name: name + line: 118 + column: 1 + text: xit +- name: name + line: 118 + column: 5 + text: "\"root xit\"" +- name: item + line: 121 + column: 1 + text: "xexample \"root xexample\" do\nend" +- name: _run + line: 121 + column: 1 + text: xexample +- name: name + line: 121 + column: 1 + text: xexample +- name: name + line: 121 + column: 10 + text: "\"root xexample\"" +- name: item + line: 124 + column: 1 + text: "xspecify \"root xspecify\" do\nend" +- name: _run + line: 124 + column: 1 + text: xspecify +- name: name + line: 124 + column: 1 + text: xspecify +- name: name + line: 124 + column: 10 + text: "\"root xspecify\"" +- name: item + line: 127 + column: 1 + text: "skip \"root skip\" do\nend" +- name: _run + line: 127 + column: 1 + text: skip +- name: name + line: 127 + column: 1 + text: skip +- name: name + line: 127 + column: 6 + text: "\"root skip\"" +- name: item + line: 130 + column: 1 + text: "pending \"root pending\" do\nend" +- name: _run + line: 130 + column: 1 + text: pending +- name: name + line: 130 + column: 1 + text: pending +- name: name + line: 130 + column: 9 + text: "\"root pending\"" +- name: item + line: 133 + column: 1 + text: "it_behaves_like \"root it_behaves_like\"" +- name: _run + line: 133 + column: 1 + text: it_behaves_like +- name: name + line: 133 + column: 1 + text: it_behaves_like +- name: name + line: 133 + column: 17 + text: "\"root it_behaves_like\"" +- name: item + line: 135 + column: 1 + text: "it_should_behave_like \"root it_should_behave_like\"" +- name: _run + line: 135 + column: 1 + text: it_should_behave_like +- name: name + line: 135 + column: 1 + text: it_should_behave_like +- name: name + line: 135 + column: 23 + text: "\"root it_should_behave_like\"" +- name: item + line: 137 + column: 1 + text: "include_context \"root include_context\"" +- name: _run + line: 137 + column: 1 + text: include_context +- name: name + line: 137 + column: 1 + text: include_context +- name: name + line: 137 + column: 17 + text: "\"root include_context\"" +- name: item + line: 139 + column: 1 + text: "include_examples \"root include_examples\"" +- name: _run + line: 139 + column: 1 + text: include_examples +- name: name + line: 139 + column: 1 + text: include_examples +- name: name + line: 139 + column: 18 + text: "\"root include_examples\"" +- name: item + line: 143 + column: 1 + text: "describe \"outer\" do\n context \"inner\" do\n it \"nested it\" do\n end\n\n specify \"nested specify\" do\n end\n\n example \"nested example\" do\n end\n\n feature \"nested feature\" do\n end\n\n scenario \"nested scenario\" do\n end\n\n shared_examples \"nested shared_examples\" do\n end\n\n fdescribe \"nested fdescribe\" do\n end\n\n fcontext \"nested fcontext\" do\n end\n\n fit \"nested fit\" do\n end\n\n fexample \"nested fexample\" do\n end\n\n focus \"nested focus\" do\n end\n\n xdescribe \"nested xdescribe\" do\n end\n\n xcontext \"nested xcontext\" do\n end\n\n xit \"nested xit\" do\n end\n\n xexample \"nested xexample\" do\n end\n\n xspecify \"nested xspecify\" do\n end\n\n skip \"nested skip\" do\n end\n\n pending \"nested pending\" do\n end\n\n it_behaves_like \"nested it_behaves_like\"\n\n it_should_behave_like \"nested it_should_behave_like\"\n\n include_context \"nested include_context\"\n\n include_examples \"nested include_examples\"\n\n it { is_expected.to be_truthy }\n it { is_expected.not_to be_nil }\n its { is_expected.to be_empty }\n specify { is_expected.to be_truthy }\n example { is_expected.to be_truthy }\n fit { is_expected.to be_truthy }\n fexample { is_expected.to be_truthy }\n focus { is_expected.to be_truthy }\n xit { is_expected.to be_truthy }\n xexample { is_expected.to be_truthy }\n xspecify { is_expected.to be_truthy }\n skip { is_expected.to be_truthy }\n pending { is_expected.to be_truthy }\n end\nend" +- name: _run + line: 143 + column: 1 + text: describe +- name: name + line: 143 + column: 1 + text: describe +- name: name + line: 143 + column: 10 + text: "\"outer\"" +- name: _ctx + line: 143 + column: 1 + text: describe +- name: item + line: 144 + column: 3 + text: "context \"inner\" do\n it \"nested it\" do\n end\n\n specify \"nested specify\" do\n end\n\n example \"nested example\" do\n end\n\n feature \"nested feature\" do\n end\n\n scenario \"nested scenario\" do\n end\n\n shared_examples \"nested shared_examples\" do\n end\n\n fdescribe \"nested fdescribe\" do\n end\n\n fcontext \"nested fcontext\" do\n end\n\n fit \"nested fit\" do\n end\n\n fexample \"nested fexample\" do\n end\n\n focus \"nested focus\" do\n end\n\n xdescribe \"nested xdescribe\" do\n end\n\n xcontext \"nested xcontext\" do\n end\n\n xit \"nested xit\" do\n end\n\n xexample \"nested xexample\" do\n end\n\n xspecify \"nested xspecify\" do\n end\n\n skip \"nested skip\" do\n end\n\n pending \"nested pending\" do\n end\n\n it_behaves_like \"nested it_behaves_like\"\n\n it_should_behave_like \"nested it_should_behave_like\"\n\n include_context \"nested include_context\"\n\n include_examples \"nested include_examples\"\n\n it { is_expected.to be_truthy }\n it { is_expected.not_to be_nil }\n its { is_expected.to be_empty }\n specify { is_expected.to be_truthy }\n example { is_expected.to be_truthy }\n fit { is_expected.to be_truthy }\n fexample { is_expected.to be_truthy }\n focus { is_expected.to be_truthy }\n xit { is_expected.to be_truthy }\n xexample { is_expected.to be_truthy }\n xspecify { is_expected.to be_truthy }\n skip { is_expected.to be_truthy }\n pending { is_expected.to be_truthy }\n end" +- name: _run + line: 144 + column: 3 + text: context +- name: name + line: 144 + column: 3 + text: context +- name: name + line: 144 + column: 11 + text: "\"inner\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 145 + column: 5 + text: "it \"nested it\" do\n end" +- name: _run + line: 145 + column: 5 + text: it +- name: name + line: 145 + column: 5 + text: it +- name: name + line: 145 + column: 8 + text: "\"nested it\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 148 + column: 5 + text: "specify \"nested specify\" do\n end" +- name: _run + line: 148 + column: 5 + text: specify +- name: name + line: 148 + column: 5 + text: specify +- name: name + line: 148 + column: 13 + text: "\"nested specify\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 151 + column: 5 + text: "example \"nested example\" do\n end" +- name: _run + line: 151 + column: 5 + text: example +- name: name + line: 151 + column: 5 + text: example +- name: name + line: 151 + column: 13 + text: "\"nested example\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 154 + column: 5 + text: "feature \"nested feature\" do\n end" +- name: _run + line: 154 + column: 5 + text: feature +- name: name + line: 154 + column: 5 + text: feature +- name: name + line: 154 + column: 13 + text: "\"nested feature\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 157 + column: 5 + text: "scenario \"nested scenario\" do\n end" +- name: _run + line: 157 + column: 5 + text: scenario +- name: name + line: 157 + column: 5 + text: scenario +- name: name + line: 157 + column: 14 + text: "\"nested scenario\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 160 + column: 5 + text: "shared_examples \"nested shared_examples\" do\n end" +- name: _run + line: 160 + column: 5 + text: shared_examples +- name: name + line: 160 + column: 5 + text: shared_examples +- name: name + line: 160 + column: 21 + text: "\"nested shared_examples\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 163 + column: 5 + text: "fdescribe \"nested fdescribe\" do\n end" +- name: _run + line: 163 + column: 5 + text: fdescribe +- name: name + line: 163 + column: 5 + text: fdescribe +- name: name + line: 163 + column: 15 + text: "\"nested fdescribe\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 166 + column: 5 + text: "fcontext \"nested fcontext\" do\n end" +- name: _run + line: 166 + column: 5 + text: fcontext +- name: name + line: 166 + column: 5 + text: fcontext +- name: name + line: 166 + column: 14 + text: "\"nested fcontext\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 169 + column: 5 + text: "fit \"nested fit\" do\n end" +- name: _run + line: 169 + column: 5 + text: fit +- name: name + line: 169 + column: 5 + text: fit +- name: name + line: 169 + column: 9 + text: "\"nested fit\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 172 + column: 5 + text: "fexample \"nested fexample\" do\n end" +- name: _run + line: 172 + column: 5 + text: fexample +- name: name + line: 172 + column: 5 + text: fexample +- name: name + line: 172 + column: 14 + text: "\"nested fexample\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 175 + column: 5 + text: "focus \"nested focus\" do\n end" +- name: _run + line: 175 + column: 5 + text: focus +- name: name + line: 175 + column: 5 + text: focus +- name: name + line: 175 + column: 11 + text: "\"nested focus\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 178 + column: 5 + text: "xdescribe \"nested xdescribe\" do\n end" +- name: _run + line: 178 + column: 5 + text: xdescribe +- name: name + line: 178 + column: 5 + text: xdescribe +- name: name + line: 178 + column: 15 + text: "\"nested xdescribe\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 181 + column: 5 + text: "xcontext \"nested xcontext\" do\n end" +- name: _run + line: 181 + column: 5 + text: xcontext +- name: name + line: 181 + column: 5 + text: xcontext +- name: name + line: 181 + column: 14 + text: "\"nested xcontext\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 184 + column: 5 + text: "xit \"nested xit\" do\n end" +- name: _run + line: 184 + column: 5 + text: xit +- name: name + line: 184 + column: 5 + text: xit +- name: name + line: 184 + column: 9 + text: "\"nested xit\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 187 + column: 5 + text: "xexample \"nested xexample\" do\n end" +- name: _run + line: 187 + column: 5 + text: xexample +- name: name + line: 187 + column: 5 + text: xexample +- name: name + line: 187 + column: 14 + text: "\"nested xexample\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 190 + column: 5 + text: "xspecify \"nested xspecify\" do\n end" +- name: _run + line: 190 + column: 5 + text: xspecify +- name: name + line: 190 + column: 5 + text: xspecify +- name: name + line: 190 + column: 14 + text: "\"nested xspecify\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 193 + column: 5 + text: "skip \"nested skip\" do\n end" +- name: _run + line: 193 + column: 5 + text: skip +- name: name + line: 193 + column: 5 + text: skip +- name: name + line: 193 + column: 10 + text: "\"nested skip\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 196 + column: 5 + text: "pending \"nested pending\" do\n end" +- name: _run + line: 196 + column: 5 + text: pending +- name: name + line: 196 + column: 5 + text: pending +- name: name + line: 196 + column: 13 + text: "\"nested pending\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 199 + column: 5 + text: "it_behaves_like \"nested it_behaves_like\"" +- name: _run + line: 199 + column: 5 + text: it_behaves_like +- name: name + line: 199 + column: 5 + text: it_behaves_like +- name: name + line: 199 + column: 21 + text: "\"nested it_behaves_like\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 201 + column: 5 + text: "it_should_behave_like \"nested it_should_behave_like\"" +- name: _run + line: 201 + column: 5 + text: it_should_behave_like +- name: name + line: 201 + column: 5 + text: it_should_behave_like +- name: name + line: 201 + column: 27 + text: "\"nested it_should_behave_like\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 203 + column: 5 + text: "include_context \"nested include_context\"" +- name: _run + line: 203 + column: 5 + text: include_context +- name: name + line: 203 + column: 5 + text: include_context +- name: name + line: 203 + column: 21 + text: "\"nested include_context\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 205 + column: 5 + text: "include_examples \"nested include_examples\"" +- name: _run + line: 205 + column: 5 + text: include_examples +- name: name + line: 205 + column: 5 + text: include_examples +- name: name + line: 205 + column: 22 + text: "\"nested include_examples\"" +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 207 + column: 5 + text: "it { is_expected.to be_truthy }" +- name: _run + line: 207 + column: 5 + text: it +- name: name + line: 207 + column: 5 + text: it +- name: name + line: 207 + column: 8 + text: "{ is_expected.to be_truthy }" +- name: _expectation + line: 207 + column: 10 + text: is_expected +- name: _negation + line: 207 + column: 22 + text: to +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 208 + column: 5 + text: "it { is_expected.not_to be_nil }" +- name: _run + line: 208 + column: 5 + text: it +- name: name + line: 208 + column: 5 + text: it +- name: name + line: 208 + column: 8 + text: "{ is_expected.not_to be_nil }" +- name: _expectation + line: 208 + column: 10 + text: is_expected +- name: _negation + line: 208 + column: 22 + text: not_to +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 209 + column: 5 + text: "its { is_expected.to be_empty }" +- name: _run + line: 209 + column: 5 + text: its +- name: name + line: 209 + column: 5 + text: its +- name: name + line: 209 + column: 9 + text: "{ is_expected.to be_empty }" +- name: _expectation + line: 209 + column: 11 + text: is_expected +- name: _negation + line: 209 + column: 23 + text: to +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 210 + column: 5 + text: "specify { is_expected.to be_truthy }" +- name: _run + line: 210 + column: 5 + text: specify +- name: name + line: 210 + column: 5 + text: specify +- name: name + line: 210 + column: 13 + text: "{ is_expected.to be_truthy }" +- name: _expectation + line: 210 + column: 15 + text: is_expected +- name: _negation + line: 210 + column: 27 + text: to +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 211 + column: 5 + text: "example { is_expected.to be_truthy }" +- name: _run + line: 211 + column: 5 + text: example +- name: name + line: 211 + column: 5 + text: example +- name: name + line: 211 + column: 13 + text: "{ is_expected.to be_truthy }" +- name: _expectation + line: 211 + column: 15 + text: is_expected +- name: _negation + line: 211 + column: 27 + text: to +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 212 + column: 5 + text: "fit { is_expected.to be_truthy }" +- name: _run + line: 212 + column: 5 + text: fit +- name: name + line: 212 + column: 5 + text: fit +- name: name + line: 212 + column: 9 + text: "{ is_expected.to be_truthy }" +- name: _expectation + line: 212 + column: 11 + text: is_expected +- name: _negation + line: 212 + column: 23 + text: to +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 213 + column: 5 + text: "fexample { is_expected.to be_truthy }" +- name: _run + line: 213 + column: 5 + text: fexample +- name: name + line: 213 + column: 5 + text: fexample +- name: name + line: 213 + column: 14 + text: "{ is_expected.to be_truthy }" +- name: _expectation + line: 213 + column: 16 + text: is_expected +- name: _negation + line: 213 + column: 28 + text: to +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 214 + column: 5 + text: "focus { is_expected.to be_truthy }" +- name: _run + line: 214 + column: 5 + text: focus +- name: name + line: 214 + column: 5 + text: focus +- name: name + line: 214 + column: 11 + text: "{ is_expected.to be_truthy }" +- name: _expectation + line: 214 + column: 13 + text: is_expected +- name: _negation + line: 214 + column: 25 + text: to +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 215 + column: 5 + text: "xit { is_expected.to be_truthy }" +- name: _run + line: 215 + column: 5 + text: xit +- name: name + line: 215 + column: 5 + text: xit +- name: name + line: 215 + column: 9 + text: "{ is_expected.to be_truthy }" +- name: _expectation + line: 215 + column: 11 + text: is_expected +- name: _negation + line: 215 + column: 23 + text: to +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 216 + column: 5 + text: "xexample { is_expected.to be_truthy }" +- name: _run + line: 216 + column: 5 + text: xexample +- name: name + line: 216 + column: 5 + text: xexample +- name: name + line: 216 + column: 14 + text: "{ is_expected.to be_truthy }" +- name: _expectation + line: 216 + column: 16 + text: is_expected +- name: _negation + line: 216 + column: 28 + text: to +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 217 + column: 5 + text: "xspecify { is_expected.to be_truthy }" +- name: _run + line: 217 + column: 5 + text: xspecify +- name: name + line: 217 + column: 5 + text: xspecify +- name: name + line: 217 + column: 14 + text: "{ is_expected.to be_truthy }" +- name: _expectation + line: 217 + column: 16 + text: is_expected +- name: _negation + line: 217 + column: 28 + text: to +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 218 + column: 5 + text: "skip { is_expected.to be_truthy }" +- name: _run + line: 218 + column: 5 + text: skip +- name: name + line: 218 + column: 5 + text: skip +- name: name + line: 218 + column: 10 + text: "{ is_expected.to be_truthy }" +- name: _expectation + line: 218 + column: 12 + text: is_expected +- name: _negation + line: 218 + column: 24 + text: to +- name: _ctx + line: 144 + column: 3 + text: context +- name: item + line: 219 + column: 5 + text: "pending { is_expected.to be_truthy }" +- name: _run + line: 219 + column: 5 + text: pending +- name: name + line: 219 + column: 5 + text: pending +- name: name + line: 219 + column: 13 + text: "{ is_expected.to be_truthy }" +- name: _expectation + line: 219 + column: 15 + text: is_expected +- name: _negation + line: 219 + column: 27 + text: to +- name: item + line: 225 + column: 1 + text: "namespace :db do\n namespace :migrate do\n task :up do\n # migrate\n end\n end\nend" +- name: _namespace + line: 225 + column: 1 + text: namespace +- name: name + line: 225 + column: 1 + text: namespace +- name: name + line: 225 + column: 11 + text: ":db" +- name: _parent_namespace + line: 225 + column: 1 + text: namespace +- name: item + line: 226 + column: 3 + text: "namespace :migrate do\n task :up do\n # migrate\n end\n end" +- name: _namespace + line: 226 + column: 3 + text: namespace +- name: name + line: 226 + column: 3 + text: namespace +- name: name + line: 226 + column: 13 + text: ":migrate" +- name: _namespace + line: 226 + column: 3 + text: namespace +- name: item + line: 227 + column: 5 + text: "task :up do\n # migrate\n end" +- name: _task + line: 227 + column: 5 + text: task +- name: name + line: 227 + column: 5 + text: task +- name: name + line: 227 + column: 10 + text: ":up" +- name: item + line: 233 + column: 1 + text: "task :version do\n # version\nend" +- name: _task + line: 233 + column: 1 + text: task +- name: name + line: 233 + column: 1 + text: task +- name: name + line: 233 + column: 6 + text: ":version" +- name: item + line: 237 + column: 1 + text: "task default: :test do\n # default\nend" +- name: _task + line: 237 + column: 1 + text: task +- name: name + line: 237 + column: 1 + text: task +- name: name + line: 237 + column: 6 + text: default diff --git a/tests/languages/ruby/snapshots/runnables.snap b/tests/languages/ruby/snapshots/runnables.snap new file mode 100644 index 0000000..4169860 --- /dev/null +++ b/tests/languages/ruby/snapshots/runnables.snap @@ -0,0 +1,2320 @@ +--- +source: tests/ruby.rs +expression: captures +--- +- name: _ruby-test + line: 9 + column: 3 + text: "it \"has an email\" do\n # test\n end" +- name: run + line: 9 + column: 3 + text: it +- name: name + line: 9 + column: 6 + text: "\"has an email\"" +- name: RUBY_TEST_NAME + line: 9 + column: 6 + text: "\"has an email\"" +- name: _ruby-test + line: 9 + column: 3 + text: "it \"has an email\" do\n # test\n end" +- name: run + line: 9 + column: 3 + text: it +- name: name + line: 9 + column: 7 + text: has an email +- name: RUBY_TEST_NAME + line: 9 + column: 7 + text: has an email +- name: _ruby-test + line: 14 + column: 1 + text: "describe \"User authentication\" do\n it \"validates email format\" do\n expect(user.email).to match(/email/)\n end\n\n context \"with invalid credentials\" do\n it \"returns an error\" do\n # test implementation\n end\n end\n\n context \"with valid credentials\" do\n it \"authenticates successfully\" do\n # test implementation\n end\n end\nend" +- name: run + line: 14 + column: 1 + text: describe +- name: name + line: 14 + column: 10 + text: "\"User authentication\"" +- name: RUBY_TEST_NAME + line: 14 + column: 10 + text: "\"User authentication\"" +- name: _ruby-test + line: 14 + column: 1 + text: "describe \"User authentication\" do\n it \"validates email format\" do\n expect(user.email).to match(/email/)\n end\n\n context \"with invalid credentials\" do\n it \"returns an error\" do\n # test implementation\n end\n end\n\n context \"with valid credentials\" do\n it \"authenticates successfully\" do\n # test implementation\n end\n end\nend" +- name: run + line: 14 + column: 1 + text: describe +- name: name + line: 14 + column: 11 + text: User authentication +- name: RUBY_TEST_NAME + line: 14 + column: 11 + text: User authentication +- name: _ruby-test + line: 15 + column: 3 + text: "it \"validates email format\" do\n expect(user.email).to match(/email/)\n end" +- name: run + line: 15 + column: 3 + text: it +- name: name + line: 15 + column: 6 + text: "\"validates email format\"" +- name: RUBY_TEST_NAME + line: 15 + column: 6 + text: "\"validates email format\"" +- name: _ruby-test + line: 15 + column: 3 + text: "it \"validates email format\" do\n expect(user.email).to match(/email/)\n end" +- name: run + line: 15 + column: 3 + text: it +- name: name + line: 15 + column: 7 + text: validates email format +- name: RUBY_TEST_NAME + line: 15 + column: 7 + text: validates email format +- name: _ruby-test + line: 19 + column: 3 + text: "context \"with invalid credentials\" do\n it \"returns an error\" do\n # test implementation\n end\n end" +- name: run + line: 19 + column: 3 + text: context +- name: name + line: 19 + column: 11 + text: "\"with invalid credentials\"" +- name: RUBY_TEST_NAME + line: 19 + column: 11 + text: "\"with invalid credentials\"" +- name: _ruby-test + line: 19 + column: 3 + text: "context \"with invalid credentials\" do\n it \"returns an error\" do\n # test implementation\n end\n end" +- name: run + line: 19 + column: 3 + text: context +- name: name + line: 19 + column: 12 + text: with invalid credentials +- name: RUBY_TEST_NAME + line: 19 + column: 12 + text: with invalid credentials +- name: _ruby-test + line: 20 + column: 5 + text: "it \"returns an error\" do\n # test implementation\n end" +- name: run + line: 20 + column: 5 + text: it +- name: name + line: 20 + column: 8 + text: "\"returns an error\"" +- name: RUBY_TEST_NAME + line: 20 + column: 8 + text: "\"returns an error\"" +- name: _ruby-test + line: 20 + column: 5 + text: "it \"returns an error\" do\n # test implementation\n end" +- name: run + line: 20 + column: 5 + text: it +- name: name + line: 20 + column: 9 + text: returns an error +- name: RUBY_TEST_NAME + line: 20 + column: 9 + text: returns an error +- name: _ruby-test + line: 25 + column: 3 + text: "context \"with valid credentials\" do\n it \"authenticates successfully\" do\n # test implementation\n end\n end" +- name: run + line: 25 + column: 3 + text: context +- name: name + line: 25 + column: 11 + text: "\"with valid credentials\"" +- name: RUBY_TEST_NAME + line: 25 + column: 11 + text: "\"with valid credentials\"" +- name: _ruby-test + line: 25 + column: 3 + text: "context \"with valid credentials\" do\n it \"authenticates successfully\" do\n # test implementation\n end\n end" +- name: run + line: 25 + column: 3 + text: context +- name: name + line: 25 + column: 12 + text: with valid credentials +- name: RUBY_TEST_NAME + line: 25 + column: 12 + text: with valid credentials +- name: _ruby-test + line: 26 + column: 5 + text: "it \"authenticates successfully\" do\n # test implementation\n end" +- name: run + line: 26 + column: 5 + text: it +- name: name + line: 26 + column: 8 + text: "\"authenticates successfully\"" +- name: RUBY_TEST_NAME + line: 26 + column: 8 + text: "\"authenticates successfully\"" +- name: _ruby-test + line: 26 + column: 5 + text: "it \"authenticates successfully\" do\n # test implementation\n end" +- name: run + line: 26 + column: 5 + text: it +- name: name + line: 26 + column: 9 + text: authenticates successfully +- name: RUBY_TEST_NAME + line: 26 + column: 9 + text: authenticates successfully +- name: _ruby-test + line: 32 + column: 1 + text: "describe \"Billing system\" do\n context \"with subscription\" do\n context \"monthly plan\" do\n it \"charges correctly\" do\n # test\n end\n\n it \"renews automatically\" do\n # test\n end\n end\n\n context \"yearly plan\" do\n it \"applies discount\" do\n # test\n end\n end\n end\n\n context \"without subscription\" do\n it \"uses free tier\" do\n # test\n end\n end\nend" +- name: run + line: 32 + column: 1 + text: describe +- name: name + line: 32 + column: 10 + text: "\"Billing system\"" +- name: RUBY_TEST_NAME + line: 32 + column: 10 + text: "\"Billing system\"" +- name: _ruby-test + line: 32 + column: 1 + text: "describe \"Billing system\" do\n context \"with subscription\" do\n context \"monthly plan\" do\n it \"charges correctly\" do\n # test\n end\n\n it \"renews automatically\" do\n # test\n end\n end\n\n context \"yearly plan\" do\n it \"applies discount\" do\n # test\n end\n end\n end\n\n context \"without subscription\" do\n it \"uses free tier\" do\n # test\n end\n end\nend" +- name: run + line: 32 + column: 1 + text: describe +- name: name + line: 32 + column: 11 + text: Billing system +- name: RUBY_TEST_NAME + line: 32 + column: 11 + text: Billing system +- name: _ruby-test + line: 33 + column: 3 + text: "context \"with subscription\" do\n context \"monthly plan\" do\n it \"charges correctly\" do\n # test\n end\n\n it \"renews automatically\" do\n # test\n end\n end\n\n context \"yearly plan\" do\n it \"applies discount\" do\n # test\n end\n end\n end" +- name: run + line: 33 + column: 3 + text: context +- name: name + line: 33 + column: 11 + text: "\"with subscription\"" +- name: RUBY_TEST_NAME + line: 33 + column: 11 + text: "\"with subscription\"" +- name: _ruby-test + line: 33 + column: 3 + text: "context \"with subscription\" do\n context \"monthly plan\" do\n it \"charges correctly\" do\n # test\n end\n\n it \"renews automatically\" do\n # test\n end\n end\n\n context \"yearly plan\" do\n it \"applies discount\" do\n # test\n end\n end\n end" +- name: run + line: 33 + column: 3 + text: context +- name: name + line: 33 + column: 12 + text: with subscription +- name: RUBY_TEST_NAME + line: 33 + column: 12 + text: with subscription +- name: _ruby-test + line: 34 + column: 5 + text: "context \"monthly plan\" do\n it \"charges correctly\" do\n # test\n end\n\n it \"renews automatically\" do\n # test\n end\n end" +- name: run + line: 34 + column: 5 + text: context +- name: name + line: 34 + column: 13 + text: "\"monthly plan\"" +- name: RUBY_TEST_NAME + line: 34 + column: 13 + text: "\"monthly plan\"" +- name: _ruby-test + line: 34 + column: 5 + text: "context \"monthly plan\" do\n it \"charges correctly\" do\n # test\n end\n\n it \"renews automatically\" do\n # test\n end\n end" +- name: run + line: 34 + column: 5 + text: context +- name: name + line: 34 + column: 14 + text: monthly plan +- name: RUBY_TEST_NAME + line: 34 + column: 14 + text: monthly plan +- name: _ruby-test + line: 35 + column: 7 + text: "it \"charges correctly\" do\n # test\n end" +- name: run + line: 35 + column: 7 + text: it +- name: name + line: 35 + column: 10 + text: "\"charges correctly\"" +- name: RUBY_TEST_NAME + line: 35 + column: 10 + text: "\"charges correctly\"" +- name: _ruby-test + line: 35 + column: 7 + text: "it \"charges correctly\" do\n # test\n end" +- name: run + line: 35 + column: 7 + text: it +- name: name + line: 35 + column: 11 + text: charges correctly +- name: RUBY_TEST_NAME + line: 35 + column: 11 + text: charges correctly +- name: _ruby-test + line: 39 + column: 7 + text: "it \"renews automatically\" do\n # test\n end" +- name: run + line: 39 + column: 7 + text: it +- name: name + line: 39 + column: 10 + text: "\"renews automatically\"" +- name: RUBY_TEST_NAME + line: 39 + column: 10 + text: "\"renews automatically\"" +- name: _ruby-test + line: 39 + column: 7 + text: "it \"renews automatically\" do\n # test\n end" +- name: run + line: 39 + column: 7 + text: it +- name: name + line: 39 + column: 11 + text: renews automatically +- name: RUBY_TEST_NAME + line: 39 + column: 11 + text: renews automatically +- name: _ruby-test + line: 44 + column: 5 + text: "context \"yearly plan\" do\n it \"applies discount\" do\n # test\n end\n end" +- name: run + line: 44 + column: 5 + text: context +- name: name + line: 44 + column: 13 + text: "\"yearly plan\"" +- name: RUBY_TEST_NAME + line: 44 + column: 13 + text: "\"yearly plan\"" +- name: _ruby-test + line: 44 + column: 5 + text: "context \"yearly plan\" do\n it \"applies discount\" do\n # test\n end\n end" +- name: run + line: 44 + column: 5 + text: context +- name: name + line: 44 + column: 14 + text: yearly plan +- name: RUBY_TEST_NAME + line: 44 + column: 14 + text: yearly plan +- name: _ruby-test + line: 45 + column: 7 + text: "it \"applies discount\" do\n # test\n end" +- name: run + line: 45 + column: 7 + text: it +- name: name + line: 45 + column: 10 + text: "\"applies discount\"" +- name: RUBY_TEST_NAME + line: 45 + column: 10 + text: "\"applies discount\"" +- name: _ruby-test + line: 45 + column: 7 + text: "it \"applies discount\" do\n # test\n end" +- name: run + line: 45 + column: 7 + text: it +- name: name + line: 45 + column: 11 + text: applies discount +- name: RUBY_TEST_NAME + line: 45 + column: 11 + text: applies discount +- name: _ruby-test + line: 51 + column: 3 + text: "context \"without subscription\" do\n it \"uses free tier\" do\n # test\n end\n end" +- name: run + line: 51 + column: 3 + text: context +- name: name + line: 51 + column: 11 + text: "\"without subscription\"" +- name: RUBY_TEST_NAME + line: 51 + column: 11 + text: "\"without subscription\"" +- name: _ruby-test + line: 51 + column: 3 + text: "context \"without subscription\" do\n it \"uses free tier\" do\n # test\n end\n end" +- name: run + line: 51 + column: 3 + text: context +- name: name + line: 51 + column: 12 + text: without subscription +- name: RUBY_TEST_NAME + line: 51 + column: 12 + text: without subscription +- name: _ruby-test + line: 52 + column: 5 + text: "it \"uses free tier\" do\n # test\n end" +- name: run + line: 52 + column: 5 + text: it +- name: name + line: 52 + column: 8 + text: "\"uses free tier\"" +- name: RUBY_TEST_NAME + line: 52 + column: 8 + text: "\"uses free tier\"" +- name: _ruby-test + line: 52 + column: 5 + text: "it \"uses free tier\" do\n # test\n end" +- name: run + line: 52 + column: 5 + text: it +- name: name + line: 52 + column: 9 + text: uses free tier +- name: RUBY_TEST_NAME + line: 52 + column: 9 + text: uses free tier +- name: _ruby-test + line: 58 + column: 1 + text: "describe \"Payment processing\" do\n fdescribe \"credit card payment\" do\n it \"processes successfully\" do\n # test\n end\n\n fit \"validates card number\" do\n # focused test\n end\n end\n\n describe \"bank transfer\" do\n fcontext \"with valid account\" do\n it \"transfers funds\" do\n # test\n end\n end\n end\nend" +- name: run + line: 58 + column: 1 + text: describe +- name: name + line: 58 + column: 10 + text: "\"Payment processing\"" +- name: RUBY_TEST_NAME + line: 58 + column: 10 + text: "\"Payment processing\"" +- name: _ruby-test + line: 58 + column: 1 + text: "describe \"Payment processing\" do\n fdescribe \"credit card payment\" do\n it \"processes successfully\" do\n # test\n end\n\n fit \"validates card number\" do\n # focused test\n end\n end\n\n describe \"bank transfer\" do\n fcontext \"with valid account\" do\n it \"transfers funds\" do\n # test\n end\n end\n end\nend" +- name: run + line: 58 + column: 1 + text: describe +- name: name + line: 58 + column: 11 + text: Payment processing +- name: RUBY_TEST_NAME + line: 58 + column: 11 + text: Payment processing +- name: _ruby-test + line: 59 + column: 3 + text: "fdescribe \"credit card payment\" do\n it \"processes successfully\" do\n # test\n end\n\n fit \"validates card number\" do\n # focused test\n end\n end" +- name: run + line: 59 + column: 3 + text: fdescribe +- name: name + line: 59 + column: 13 + text: "\"credit card payment\"" +- name: RUBY_TEST_NAME + line: 59 + column: 13 + text: "\"credit card payment\"" +- name: _ruby-test + line: 59 + column: 3 + text: "fdescribe \"credit card payment\" do\n it \"processes successfully\" do\n # test\n end\n\n fit \"validates card number\" do\n # focused test\n end\n end" +- name: run + line: 59 + column: 3 + text: fdescribe +- name: name + line: 59 + column: 14 + text: credit card payment +- name: RUBY_TEST_NAME + line: 59 + column: 14 + text: credit card payment +- name: _ruby-test + line: 60 + column: 5 + text: "it \"processes successfully\" do\n # test\n end" +- name: run + line: 60 + column: 5 + text: it +- name: name + line: 60 + column: 8 + text: "\"processes successfully\"" +- name: RUBY_TEST_NAME + line: 60 + column: 8 + text: "\"processes successfully\"" +- name: _ruby-test + line: 60 + column: 5 + text: "it \"processes successfully\" do\n # test\n end" +- name: run + line: 60 + column: 5 + text: it +- name: name + line: 60 + column: 9 + text: processes successfully +- name: RUBY_TEST_NAME + line: 60 + column: 9 + text: processes successfully +- name: _ruby-test + line: 64 + column: 5 + text: "fit \"validates card number\" do\n # focused test\n end" +- name: run + line: 64 + column: 5 + text: fit +- name: name + line: 64 + column: 9 + text: "\"validates card number\"" +- name: RUBY_TEST_NAME + line: 64 + column: 9 + text: "\"validates card number\"" +- name: _ruby-test + line: 64 + column: 5 + text: "fit \"validates card number\" do\n # focused test\n end" +- name: run + line: 64 + column: 5 + text: fit +- name: name + line: 64 + column: 10 + text: validates card number +- name: RUBY_TEST_NAME + line: 64 + column: 10 + text: validates card number +- name: _ruby-test + line: 69 + column: 3 + text: "describe \"bank transfer\" do\n fcontext \"with valid account\" do\n it \"transfers funds\" do\n # test\n end\n end\n end" +- name: run + line: 69 + column: 3 + text: describe +- name: name + line: 69 + column: 12 + text: "\"bank transfer\"" +- name: RUBY_TEST_NAME + line: 69 + column: 12 + text: "\"bank transfer\"" +- name: _ruby-test + line: 69 + column: 3 + text: "describe \"bank transfer\" do\n fcontext \"with valid account\" do\n it \"transfers funds\" do\n # test\n end\n end\n end" +- name: run + line: 69 + column: 3 + text: describe +- name: name + line: 69 + column: 13 + text: bank transfer +- name: RUBY_TEST_NAME + line: 69 + column: 13 + text: bank transfer +- name: _ruby-test + line: 70 + column: 5 + text: "fcontext \"with valid account\" do\n it \"transfers funds\" do\n # test\n end\n end" +- name: run + line: 70 + column: 5 + text: fcontext +- name: name + line: 70 + column: 14 + text: "\"with valid account\"" +- name: RUBY_TEST_NAME + line: 70 + column: 14 + text: "\"with valid account\"" +- name: _ruby-test + line: 70 + column: 5 + text: "fcontext \"with valid account\" do\n it \"transfers funds\" do\n # test\n end\n end" +- name: run + line: 70 + column: 5 + text: fcontext +- name: name + line: 70 + column: 15 + text: with valid account +- name: RUBY_TEST_NAME + line: 70 + column: 15 + text: with valid account +- name: _ruby-test + line: 71 + column: 7 + text: "it \"transfers funds\" do\n # test\n end" +- name: run + line: 71 + column: 7 + text: it +- name: name + line: 71 + column: 10 + text: "\"transfers funds\"" +- name: RUBY_TEST_NAME + line: 71 + column: 10 + text: "\"transfers funds\"" +- name: _ruby-test + line: 71 + column: 7 + text: "it \"transfers funds\" do\n # test\n end" +- name: run + line: 71 + column: 7 + text: it +- name: name + line: 71 + column: 11 + text: transfers funds +- name: RUBY_TEST_NAME + line: 71 + column: 11 + text: transfers funds +- name: _ruby-test + line: 78 + column: 1 + text: "describe \"Admin\" do\n it_behaves_like \"a valid user\"\n\n it \"has admin privileges\" do\n # test\n end\nend" +- name: run + line: 78 + column: 1 + text: describe +- name: name + line: 78 + column: 10 + text: "\"Admin\"" +- name: RUBY_TEST_NAME + line: 78 + column: 10 + text: "\"Admin\"" +- name: _ruby-test + line: 78 + column: 1 + text: "describe \"Admin\" do\n it_behaves_like \"a valid user\"\n\n it \"has admin privileges\" do\n # test\n end\nend" +- name: run + line: 78 + column: 1 + text: describe +- name: name + line: 78 + column: 11 + text: Admin +- name: RUBY_TEST_NAME + line: 78 + column: 11 + text: Admin +- name: _ruby-test + line: 79 + column: 3 + text: "it_behaves_like \"a valid user\"" +- name: run + line: 79 + column: 3 + text: it_behaves_like +- name: name + line: 79 + column: 19 + text: "\"a valid user\"" +- name: RUBY_TEST_NAME + line: 79 + column: 19 + text: "\"a valid user\"" +- name: _ruby-test + line: 79 + column: 3 + text: "it_behaves_like \"a valid user\"" +- name: run + line: 79 + column: 3 + text: it_behaves_like +- name: name + line: 79 + column: 20 + text: a valid user +- name: RUBY_TEST_NAME + line: 79 + column: 20 + text: a valid user +- name: _ruby-test + line: 81 + column: 3 + text: "it \"has admin privileges\" do\n # test\n end" +- name: run + line: 81 + column: 3 + text: it +- name: name + line: 81 + column: 6 + text: "\"has admin privileges\"" +- name: RUBY_TEST_NAME + line: 81 + column: 6 + text: "\"has admin privileges\"" +- name: _ruby-test + line: 81 + column: 3 + text: "it \"has admin privileges\" do\n # test\n end" +- name: run + line: 81 + column: 3 + text: it +- name: name + line: 81 + column: 7 + text: has admin privileges +- name: RUBY_TEST_NAME + line: 81 + column: 7 + text: has admin privileges +- name: _ruby-test + line: 86 + column: 1 + text: "describe \"Customer\" do\n include_examples \"a valid user\"\n\n it \"can place orders\" do\n # test\n end\nend" +- name: run + line: 86 + column: 1 + text: describe +- name: name + line: 86 + column: 10 + text: "\"Customer\"" +- name: RUBY_TEST_NAME + line: 86 + column: 10 + text: "\"Customer\"" +- name: _ruby-test + line: 86 + column: 1 + text: "describe \"Customer\" do\n include_examples \"a valid user\"\n\n it \"can place orders\" do\n # test\n end\nend" +- name: run + line: 86 + column: 1 + text: describe +- name: name + line: 86 + column: 11 + text: Customer +- name: RUBY_TEST_NAME + line: 86 + column: 11 + text: Customer +- name: _ruby-test + line: 87 + column: 3 + text: "include_examples \"a valid user\"" +- name: run + line: 87 + column: 3 + text: include_examples +- name: name + line: 87 + column: 20 + text: "\"a valid user\"" +- name: RUBY_TEST_NAME + line: 87 + column: 20 + text: "\"a valid user\"" +- name: _ruby-test + line: 87 + column: 3 + text: "include_examples \"a valid user\"" +- name: run + line: 87 + column: 3 + text: include_examples +- name: name + line: 87 + column: 21 + text: a valid user +- name: RUBY_TEST_NAME + line: 87 + column: 21 + text: a valid user +- name: _ruby-test + line: 89 + column: 3 + text: "it \"can place orders\" do\n # test\n end" +- name: run + line: 89 + column: 3 + text: it +- name: name + line: 89 + column: 6 + text: "\"can place orders\"" +- name: RUBY_TEST_NAME + line: 89 + column: 6 + text: "\"can place orders\"" +- name: _ruby-test + line: 89 + column: 3 + text: "it \"can place orders\" do\n # test\n end" +- name: run + line: 89 + column: 3 + text: it +- name: name + line: 89 + column: 7 + text: can place orders +- name: RUBY_TEST_NAME + line: 89 + column: 7 + text: can place orders +- name: _ruby-test + line: 94 + column: 1 + text: "describe \"Guest\" do\n include_context \"guest session\"\n\n it \"has limited access\" do\n # test\n end\nend" +- name: run + line: 94 + column: 1 + text: describe +- name: name + line: 94 + column: 10 + text: "\"Guest\"" +- name: RUBY_TEST_NAME + line: 94 + column: 10 + text: "\"Guest\"" +- name: _ruby-test + line: 94 + column: 1 + text: "describe \"Guest\" do\n include_context \"guest session\"\n\n it \"has limited access\" do\n # test\n end\nend" +- name: run + line: 94 + column: 1 + text: describe +- name: name + line: 94 + column: 11 + text: Guest +- name: RUBY_TEST_NAME + line: 94 + column: 11 + text: Guest +- name: _ruby-test + line: 95 + column: 3 + text: "include_context \"guest session\"" +- name: run + line: 95 + column: 3 + text: include_context +- name: name + line: 95 + column: 19 + text: "\"guest session\"" +- name: RUBY_TEST_NAME + line: 95 + column: 19 + text: "\"guest session\"" +- name: _ruby-test + line: 95 + column: 3 + text: "include_context \"guest session\"" +- name: run + line: 95 + column: 3 + text: include_context +- name: name + line: 95 + column: 20 + text: guest session +- name: RUBY_TEST_NAME + line: 95 + column: 20 + text: guest session +- name: _ruby-test + line: 97 + column: 3 + text: "it \"has limited access\" do\n # test\n end" +- name: run + line: 97 + column: 3 + text: it +- name: name + line: 97 + column: 6 + text: "\"has limited access\"" +- name: RUBY_TEST_NAME + line: 97 + column: 6 + text: "\"has limited access\"" +- name: _ruby-test + line: 97 + column: 3 + text: "it \"has limited access\" do\n # test\n end" +- name: run + line: 97 + column: 3 + text: it +- name: name + line: 97 + column: 7 + text: has limited access +- name: RUBY_TEST_NAME + line: 97 + column: 7 + text: has limited access +- name: _ruby-test + line: 102 + column: 1 + text: "describe UserService do\n it \"processes requests\" do\n # test\n end\nend" +- name: run + line: 102 + column: 1 + text: describe +- name: name + line: 102 + column: 10 + text: UserService +- name: RUBY_TEST_NAME + line: 102 + column: 10 + text: UserService +- name: _ruby-test + line: 103 + column: 3 + text: "it \"processes requests\" do\n # test\n end" +- name: run + line: 103 + column: 3 + text: it +- name: name + line: 103 + column: 6 + text: "\"processes requests\"" +- name: RUBY_TEST_NAME + line: 103 + column: 6 + text: "\"processes requests\"" +- name: _ruby-test + line: 103 + column: 3 + text: "it \"processes requests\" do\n # test\n end" +- name: run + line: 103 + column: 3 + text: it +- name: name + line: 103 + column: 7 + text: processes requests +- name: RUBY_TEST_NAME + line: 103 + column: 7 + text: processes requests +- name: _ruby-test + line: 108 + column: 1 + text: "describe API::V1::UsersController do\n it \"returns user list\" do\n # test\n end\nend" +- name: run + line: 108 + column: 1 + text: describe +- name: name + line: 108 + column: 10 + text: "API::V1::UsersController" +- name: RUBY_TEST_NAME + line: 108 + column: 10 + text: "API::V1::UsersController" +- name: _ruby-test + line: 109 + column: 3 + text: "it \"returns user list\" do\n # test\n end" +- name: run + line: 109 + column: 3 + text: it +- name: name + line: 109 + column: 6 + text: "\"returns user list\"" +- name: RUBY_TEST_NAME + line: 109 + column: 6 + text: "\"returns user list\"" +- name: _ruby-test + line: 109 + column: 3 + text: "it \"returns user list\" do\n # test\n end" +- name: run + line: 109 + column: 3 + text: it +- name: name + line: 109 + column: 7 + text: returns user list +- name: RUBY_TEST_NAME + line: 109 + column: 7 + text: returns user list +- name: _ruby-test + line: 114 + column: 1 + text: "describe SomeConstant do\n it \"has correct value\" do\n # test\n end\nend" +- name: run + line: 114 + column: 1 + text: describe +- name: name + line: 114 + column: 10 + text: SomeConstant +- name: RUBY_TEST_NAME + line: 114 + column: 10 + text: SomeConstant +- name: _ruby-test + line: 115 + column: 3 + text: "it \"has correct value\" do\n # test\n end" +- name: run + line: 115 + column: 3 + text: it +- name: name + line: 115 + column: 6 + text: "\"has correct value\"" +- name: RUBY_TEST_NAME + line: 115 + column: 6 + text: "\"has correct value\"" +- name: _ruby-test + line: 115 + column: 3 + text: "it \"has correct value\" do\n # test\n end" +- name: run + line: 115 + column: 3 + text: it +- name: name + line: 115 + column: 7 + text: has correct value +- name: RUBY_TEST_NAME + line: 115 + column: 7 + text: has correct value +- name: _ruby-test + line: 120 + column: 1 + text: "describe :user_service do\n it :creates_user do\n # test\n end\n\n context :with_validation do\n it :validates_email do\n # test\n end\n end\nend" +- name: run + line: 120 + column: 1 + text: describe +- name: name + line: 120 + column: 10 + text: ":user_service" +- name: RUBY_TEST_NAME + line: 120 + column: 10 + text: ":user_service" +- name: _ruby-test + line: 121 + column: 3 + text: "it :creates_user do\n # test\n end" +- name: run + line: 121 + column: 3 + text: it +- name: name + line: 121 + column: 6 + text: ":creates_user" +- name: RUBY_TEST_NAME + line: 121 + column: 6 + text: ":creates_user" +- name: _ruby-test + line: 125 + column: 3 + text: "context :with_validation do\n it :validates_email do\n # test\n end\n end" +- name: run + line: 125 + column: 3 + text: context +- name: name + line: 125 + column: 11 + text: ":with_validation" +- name: RUBY_TEST_NAME + line: 125 + column: 11 + text: ":with_validation" +- name: _ruby-test + line: 126 + column: 5 + text: "it :validates_email do\n # test\n end" +- name: run + line: 126 + column: 5 + text: it +- name: name + line: 126 + column: 8 + text: ":validates_email" +- name: RUBY_TEST_NAME + line: 126 + column: 8 + text: ":validates_email" +- name: _ruby-test + line: 132 + column: 1 + text: "describe 123 do\n it \"handles numeric names\" do\n # test\n end\nend" +- name: run + line: 132 + column: 1 + text: describe +- name: name + line: 132 + column: 10 + text: "123" +- name: RUBY_TEST_NAME + line: 132 + column: 10 + text: "123" +- name: _ruby-test + line: 133 + column: 3 + text: "it \"handles numeric names\" do\n # test\n end" +- name: run + line: 133 + column: 3 + text: it +- name: name + line: 133 + column: 6 + text: "\"handles numeric names\"" +- name: RUBY_TEST_NAME + line: 133 + column: 6 + text: "\"handles numeric names\"" +- name: _ruby-test + line: 133 + column: 3 + text: "it \"handles numeric names\" do\n # test\n end" +- name: run + line: 133 + column: 3 + text: it +- name: name + line: 133 + column: 7 + text: handles numeric names +- name: RUBY_TEST_NAME + line: 133 + column: 7 + text: handles numeric names +- name: _ruby-test + line: 138 + column: 1 + text: "feature \"Checkout flow\" do\n scenario \"guest can buy\" do\n specify \"shows tax breakdown\" do\n # test\n end\n\n example \"calculates totals\" do\n # test\n end\n end\nend" +- name: run + line: 138 + column: 1 + text: feature +- name: name + line: 138 + column: 9 + text: "\"Checkout flow\"" +- name: RUBY_TEST_NAME + line: 138 + column: 9 + text: "\"Checkout flow\"" +- name: _ruby-test + line: 138 + column: 1 + text: "feature \"Checkout flow\" do\n scenario \"guest can buy\" do\n specify \"shows tax breakdown\" do\n # test\n end\n\n example \"calculates totals\" do\n # test\n end\n end\nend" +- name: run + line: 138 + column: 1 + text: feature +- name: name + line: 138 + column: 10 + text: Checkout flow +- name: RUBY_TEST_NAME + line: 138 + column: 10 + text: Checkout flow +- name: _ruby-test + line: 139 + column: 3 + text: "scenario \"guest can buy\" do\n specify \"shows tax breakdown\" do\n # test\n end\n\n example \"calculates totals\" do\n # test\n end\n end" +- name: run + line: 139 + column: 3 + text: scenario +- name: name + line: 139 + column: 12 + text: "\"guest can buy\"" +- name: RUBY_TEST_NAME + line: 139 + column: 12 + text: "\"guest can buy\"" +- name: _ruby-test + line: 139 + column: 3 + text: "scenario \"guest can buy\" do\n specify \"shows tax breakdown\" do\n # test\n end\n\n example \"calculates totals\" do\n # test\n end\n end" +- name: run + line: 139 + column: 3 + text: scenario +- name: name + line: 139 + column: 13 + text: guest can buy +- name: RUBY_TEST_NAME + line: 139 + column: 13 + text: guest can buy +- name: _ruby-test + line: 140 + column: 5 + text: "specify \"shows tax breakdown\" do\n # test\n end" +- name: run + line: 140 + column: 5 + text: specify +- name: name + line: 140 + column: 13 + text: "\"shows tax breakdown\"" +- name: RUBY_TEST_NAME + line: 140 + column: 13 + text: "\"shows tax breakdown\"" +- name: _ruby-test + line: 140 + column: 5 + text: "specify \"shows tax breakdown\" do\n # test\n end" +- name: run + line: 140 + column: 5 + text: specify +- name: name + line: 140 + column: 14 + text: shows tax breakdown +- name: RUBY_TEST_NAME + line: 140 + column: 14 + text: shows tax breakdown +- name: _ruby-test + line: 144 + column: 5 + text: "example \"calculates totals\" do\n # test\n end" +- name: run + line: 144 + column: 5 + text: example +- name: name + line: 144 + column: 13 + text: "\"calculates totals\"" +- name: RUBY_TEST_NAME + line: 144 + column: 13 + text: "\"calculates totals\"" +- name: _ruby-test + line: 144 + column: 5 + text: "example \"calculates totals\" do\n # test\n end" +- name: run + line: 144 + column: 5 + text: example +- name: name + line: 144 + column: 14 + text: calculates totals +- name: RUBY_TEST_NAME + line: 144 + column: 14 + text: calculates totals +- name: _ruby-test + line: 150 + column: 1 + text: "fexample \"focused example\" do\n # test\nend" +- name: run + line: 150 + column: 1 + text: fexample +- name: name + line: 150 + column: 10 + text: "\"focused example\"" +- name: RUBY_TEST_NAME + line: 150 + column: 10 + text: "\"focused example\"" +- name: _ruby-test + line: 150 + column: 1 + text: "fexample \"focused example\" do\n # test\nend" +- name: run + line: 150 + column: 1 + text: fexample +- name: name + line: 150 + column: 11 + text: focused example +- name: RUBY_TEST_NAME + line: 150 + column: 11 + text: focused example +- name: _ruby-test + line: 154 + column: 1 + text: "focus \"explicit focus\" do\n # test\nend" +- name: run + line: 154 + column: 1 + text: focus +- name: name + line: 154 + column: 7 + text: "\"explicit focus\"" +- name: RUBY_TEST_NAME + line: 154 + column: 7 + text: "\"explicit focus\"" +- name: _ruby-test + line: 154 + column: 1 + text: "focus \"explicit focus\" do\n # test\nend" +- name: run + line: 154 + column: 1 + text: focus +- name: name + line: 154 + column: 8 + text: explicit focus +- name: RUBY_TEST_NAME + line: 154 + column: 8 + text: explicit focus +- name: _ruby-test + line: 158 + column: 1 + text: "describe \"Shared behavior\" do\n it_should_behave_like \"a purchasable item\"\nend" +- name: run + line: 158 + column: 1 + text: describe +- name: name + line: 158 + column: 10 + text: "\"Shared behavior\"" +- name: RUBY_TEST_NAME + line: 158 + column: 10 + text: "\"Shared behavior\"" +- name: _ruby-test + line: 158 + column: 1 + text: "describe \"Shared behavior\" do\n it_should_behave_like \"a purchasable item\"\nend" +- name: run + line: 158 + column: 1 + text: describe +- name: name + line: 158 + column: 11 + text: Shared behavior +- name: RUBY_TEST_NAME + line: 158 + column: 11 + text: Shared behavior +- name: _ruby-test + line: 159 + column: 3 + text: "it_should_behave_like \"a purchasable item\"" +- name: run + line: 159 + column: 3 + text: it_should_behave_like +- name: name + line: 159 + column: 25 + text: "\"a purchasable item\"" +- name: RUBY_TEST_NAME + line: 159 + column: 25 + text: "\"a purchasable item\"" +- name: _ruby-test + line: 159 + column: 3 + text: "it_should_behave_like \"a purchasable item\"" +- name: run + line: 159 + column: 3 + text: it_should_behave_like +- name: name + line: 159 + column: 26 + text: a purchasable item +- name: RUBY_TEST_NAME + line: 159 + column: 26 + text: a purchasable item +- name: _ruby-test + line: 162 + column: 1 + text: "describe User do\n subject { User.new(email: \"test@example.com\") }\n\n it { is_expected.to be_valid }\n it { is_expected.to respond_to(:email) }\n its(:email) { is_expected.to include(\"@\") }\n\n describe \"validations\" do\n it { is_expected.to validate_presence_of(:email) }\n end\nend" +- name: run + line: 162 + column: 1 + text: describe +- name: name + line: 162 + column: 10 + text: User +- name: RUBY_TEST_NAME + line: 162 + column: 10 + text: User +- name: _ruby-test + line: 165 + column: 3 + text: "it { is_expected.to be_valid }" +- name: run + line: 165 + column: 3 + text: it +- name: name + line: 165 + column: 6 + text: "{ is_expected.to be_valid }" +- name: RUBY_TEST_NAME + line: 165 + column: 6 + text: "{ is_expected.to be_valid }" +- name: _ruby-test + line: 166 + column: 3 + text: "it { is_expected.to respond_to(:email) }" +- name: run + line: 166 + column: 3 + text: it +- name: name + line: 166 + column: 6 + text: "{ is_expected.to respond_to(:email) }" +- name: RUBY_TEST_NAME + line: 166 + column: 6 + text: "{ is_expected.to respond_to(:email) }" +- name: _ruby-test + line: 167 + column: 3 + text: "its(:email) { is_expected.to include(\"@\") }" +- name: run + line: 167 + column: 3 + text: its +- name: name + line: 167 + column: 7 + text: ":email" +- name: RUBY_TEST_NAME + line: 167 + column: 7 + text: ":email" +- name: _ruby-test + line: 169 + column: 3 + text: "describe \"validations\" do\n it { is_expected.to validate_presence_of(:email) }\n end" +- name: run + line: 169 + column: 3 + text: describe +- name: name + line: 169 + column: 12 + text: "\"validations\"" +- name: RUBY_TEST_NAME + line: 169 + column: 12 + text: "\"validations\"" +- name: _ruby-test + line: 169 + column: 3 + text: "describe \"validations\" do\n it { is_expected.to validate_presence_of(:email) }\n end" +- name: run + line: 169 + column: 3 + text: describe +- name: name + line: 169 + column: 13 + text: validations +- name: RUBY_TEST_NAME + line: 169 + column: 13 + text: validations +- name: _ruby-test + line: 170 + column: 5 + text: "it { is_expected.to validate_presence_of(:email) }" +- name: run + line: 170 + column: 5 + text: it +- name: name + line: 170 + column: 8 + text: "{ is_expected.to validate_presence_of(:email) }" +- name: RUBY_TEST_NAME + line: 170 + column: 8 + text: "{ is_expected.to validate_presence_of(:email) }" +- name: _ruby-test + line: 174 + column: 1 + text: "describe \"One-liners extra\" do\n specify { expect(true).to be(true) }\n example { expect(1).to eq(1) }\n fit { expect(2).to eq(2) }\n fexample { expect(3).to eq(3) }\n focus { expect(4).to eq(4) }\n its { is_expected.to be_nil }\nend" +- name: run + line: 174 + column: 1 + text: describe +- name: name + line: 174 + column: 10 + text: "\"One-liners extra\"" +- name: RUBY_TEST_NAME + line: 174 + column: 10 + text: "\"One-liners extra\"" +- name: _ruby-test + line: 174 + column: 1 + text: "describe \"One-liners extra\" do\n specify { expect(true).to be(true) }\n example { expect(1).to eq(1) }\n fit { expect(2).to eq(2) }\n fexample { expect(3).to eq(3) }\n focus { expect(4).to eq(4) }\n its { is_expected.to be_nil }\nend" +- name: run + line: 174 + column: 1 + text: describe +- name: name + line: 174 + column: 11 + text: One-liners extra +- name: RUBY_TEST_NAME + line: 174 + column: 11 + text: One-liners extra +- name: _ruby-test + line: 175 + column: 3 + text: "specify { expect(true).to be(true) }" +- name: run + line: 175 + column: 3 + text: specify +- name: name + line: 175 + column: 11 + text: "{ expect(true).to be(true) }" +- name: RUBY_TEST_NAME + line: 175 + column: 11 + text: "{ expect(true).to be(true) }" +- name: _ruby-test + line: 176 + column: 3 + text: "example { expect(1).to eq(1) }" +- name: run + line: 176 + column: 3 + text: example +- name: name + line: 176 + column: 11 + text: "{ expect(1).to eq(1) }" +- name: RUBY_TEST_NAME + line: 176 + column: 11 + text: "{ expect(1).to eq(1) }" +- name: _ruby-test + line: 177 + column: 3 + text: "fit { expect(2).to eq(2) }" +- name: run + line: 177 + column: 3 + text: fit +- name: name + line: 177 + column: 7 + text: "{ expect(2).to eq(2) }" +- name: RUBY_TEST_NAME + line: 177 + column: 7 + text: "{ expect(2).to eq(2) }" +- name: _ruby-test + line: 178 + column: 3 + text: "fexample { expect(3).to eq(3) }" +- name: run + line: 178 + column: 3 + text: fexample +- name: name + line: 178 + column: 12 + text: "{ expect(3).to eq(3) }" +- name: RUBY_TEST_NAME + line: 178 + column: 12 + text: "{ expect(3).to eq(3) }" +- name: _ruby-test + line: 179 + column: 3 + text: "focus { expect(4).to eq(4) }" +- name: run + line: 179 + column: 3 + text: focus +- name: name + line: 179 + column: 9 + text: "{ expect(4).to eq(4) }" +- name: RUBY_TEST_NAME + line: 179 + column: 9 + text: "{ expect(4).to eq(4) }" +- name: _ruby-test + line: 180 + column: 3 + text: "its { is_expected.to be_nil }" +- name: run + line: 180 + column: 3 + text: its +- name: name + line: 180 + column: 7 + text: "{ is_expected.to be_nil }" +- name: RUBY_TEST_NAME + line: 180 + column: 7 + text: "{ is_expected.to be_nil }" +- name: _ruby-test + line: 185 + column: 1 + text: "class UserTest < Minitest::Test\n def test_creates_user\n # test\n end\n\n def test_validates_email\n # test\n end\n\n def test_saves_to_database\n # test\n end\nend" +- name: run + line: 185 + column: 7 + text: UserTest +- name: name + line: 185 + column: 7 + text: UserTest +- name: RUBY_TEST_NAME + line: 185 + column: 7 + text: UserTest +- name: superclass + line: 185 + column: 18 + text: "Minitest::Test" +- name: _ruby-test + line: 186 + column: 3 + text: "def test_creates_user\n # test\n end" +- name: run + line: 186 + column: 7 + text: test_creates_user +- name: name + line: 186 + column: 7 + text: test_creates_user +- name: RUBY_TEST_NAME + line: 186 + column: 7 + text: test_creates_user +- name: _ruby-test + line: 190 + column: 3 + text: "def test_validates_email\n # test\n end" +- name: run + line: 190 + column: 7 + text: test_validates_email +- name: name + line: 190 + column: 7 + text: test_validates_email +- name: RUBY_TEST_NAME + line: 190 + column: 7 + text: test_validates_email +- name: _ruby-test + line: 194 + column: 3 + text: "def test_saves_to_database\n # test\n end" +- name: run + line: 194 + column: 7 + text: test_saves_to_database +- name: name + line: 194 + column: 7 + text: test_saves_to_database +- name: RUBY_TEST_NAME + line: 194 + column: 7 + text: test_saves_to_database +- name: _ruby-test + line: 199 + column: 1 + text: "class ProductTest < Minitest::Test\n test \"creates product\" do\n # test\n end\n\n test \"validates price\" do\n # test\n end\n\n test \"calculates discount\" do\n # test\n end\nend" +- name: run + line: 199 + column: 7 + text: ProductTest +- name: name + line: 199 + column: 7 + text: ProductTest +- name: RUBY_TEST_NAME + line: 199 + column: 7 + text: ProductTest +- name: superclass + line: 199 + column: 21 + text: "Minitest::Test" +- name: _ruby-test + line: 200 + column: 3 + text: "test \"creates product\" do\n # test\n end" +- name: run + line: 200 + column: 3 + text: test +- name: name + line: 200 + column: 9 + text: creates product +- name: RUBY_TEST_NAME + line: 200 + column: 9 + text: creates product +- name: _ruby-test + line: 204 + column: 3 + text: "test \"validates price\" do\n # test\n end" +- name: run + line: 204 + column: 3 + text: test +- name: name + line: 204 + column: 9 + text: validates price +- name: RUBY_TEST_NAME + line: 204 + column: 9 + text: validates price +- name: _ruby-test + line: 208 + column: 3 + text: "test \"calculates discount\" do\n # test\n end" +- name: run + line: 208 + column: 3 + text: test +- name: name + line: 208 + column: 9 + text: calculates discount +- name: RUBY_TEST_NAME + line: 208 + column: 9 + text: calculates discount +- name: _ruby-test + line: 213 + column: 1 + text: "class UsersIntegrationTest < ActionDispatch::IntegrationTest\n def test_user_signup_flow\n # test\n end\nend" +- name: run + line: 213 + column: 7 + text: UsersIntegrationTest +- name: name + line: 213 + column: 7 + text: UsersIntegrationTest +- name: RUBY_TEST_NAME + line: 213 + column: 7 + text: UsersIntegrationTest +- name: superclass + line: 213 + column: 30 + text: "ActionDispatch::IntegrationTest" +- name: _ruby-test + line: 214 + column: 3 + text: "def test_user_signup_flow\n # test\n end" +- name: run + line: 214 + column: 7 + text: test_user_signup_flow +- name: name + line: 214 + column: 7 + text: test_user_signup_flow +- name: RUBY_TEST_NAME + line: 214 + column: 7 + text: test_user_signup_flow +- name: _ruby-test + line: 219 + column: 1 + text: "class UserSystemTest < ApplicationSystemTestCase\n def test_user_can_login\n # test\n end\nend" +- name: run + line: 219 + column: 7 + text: UserSystemTest +- name: name + line: 219 + column: 7 + text: UserSystemTest +- name: RUBY_TEST_NAME + line: 219 + column: 7 + text: UserSystemTest +- name: superclass + line: 219 + column: 22 + text: "< ApplicationSystemTestCase" +- name: _ruby-test + line: 220 + column: 3 + text: "def test_user_can_login\n # test\n end" +- name: run + line: 220 + column: 7 + text: test_user_can_login +- name: name + line: 220 + column: 7 + text: test_user_can_login +- name: RUBY_TEST_NAME + line: 220 + column: 7 + text: test_user_can_login +- name: _ruby-test + line: 225 + column: 1 + text: "class AdminTest < ActiveSupport::TestCase\n def test_admin_permissions\n # test\n end\nend" +- name: run + line: 225 + column: 7 + text: AdminTest +- name: name + line: 225 + column: 7 + text: AdminTest +- name: RUBY_TEST_NAME + line: 225 + column: 7 + text: AdminTest +- name: superclass + line: 225 + column: 19 + text: "ActiveSupport::TestCase" +- name: _ruby-test + line: 226 + column: 3 + text: "def test_admin_permissions\n # test\n end" +- name: run + line: 226 + column: 7 + text: test_admin_permissions +- name: name + line: 226 + column: 7 + text: test_admin_permissions +- name: RUBY_TEST_NAME + line: 226 + column: 7 + text: test_admin_permissions +- name: _ruby-test + line: 231 + column: 1 + text: "class SystemHealthTest < ::SystemTestCase\n def test_system_health\n # test\n end\nend" +- name: run + line: 231 + column: 7 + text: SystemHealthTest +- name: name + line: 231 + column: 7 + text: SystemHealthTest +- name: RUBY_TEST_NAME + line: 231 + column: 7 + text: SystemHealthTest +- name: superclass + line: 231 + column: 26 + text: "::SystemTestCase" +- name: _ruby-test + line: 232 + column: 3 + text: "def test_system_health\n # test\n end" +- name: run + line: 232 + column: 7 + text: test_system_health +- name: name + line: 232 + column: 7 + text: test_system_health +- name: RUBY_TEST_NAME + line: 232 + column: 7 + text: test_system_health +- name: _ruby-test + line: 237 + column: 1 + text: "class QuickCheckTest < ::TLDR\n def test_quick_checks\n # test\n end\nend" +- name: run + line: 237 + column: 7 + text: QuickCheckTest +- name: name + line: 237 + column: 7 + text: QuickCheckTest +- name: RUBY_TEST_NAME + line: 237 + column: 7 + text: QuickCheckTest +- name: superclass + line: 237 + column: 24 + text: "::TLDR" +- name: _ruby-test + line: 238 + column: 3 + text: "def test_quick_checks\n # test\n end" +- name: run + line: 238 + column: 7 + text: test_quick_checks +- name: name + line: 238 + column: 7 + text: test_quick_checks +- name: RUBY_TEST_NAME + line: 238 + column: 7 + text: test_quick_checks +- name: _ruby-test + line: 243 + column: 1 + text: "class Admin::UserTest < ActiveSupport::TestCase\n def test_scoped_class_name\n # test\n end\nend" +- name: run + line: 243 + column: 14 + text: UserTest +- name: superclass + line: 243 + column: 25 + text: "ActiveSupport::TestCase" +- name: _ruby-test + line: 244 + column: 3 + text: "def test_scoped_class_name\n # test\n end" +- name: run + line: 244 + column: 7 + text: test_scoped_class_name +- name: name + line: 244 + column: 7 + text: test_scoped_class_name +- name: RUBY_TEST_NAME + line: 244 + column: 7 + text: test_scoped_class_name +- name: _ruby-test + line: 251 + column: 1 + text: "describe \"Edge cases\" do\n it \"handles empty blocks\" do\n end\n\n it \"handles special characters !@#$%^&*()\" do\n # test\n end\n\n it \"handles multiline\n string names\" do\n # test\n end\n\n it do\n # one-liner with empty name block\n end\nend" +- name: run + line: 251 + column: 1 + text: describe +- name: name + line: 251 + column: 10 + text: "\"Edge cases\"" +- name: RUBY_TEST_NAME + line: 251 + column: 10 + text: "\"Edge cases\"" +- name: _ruby-test + line: 251 + column: 1 + text: "describe \"Edge cases\" do\n it \"handles empty blocks\" do\n end\n\n it \"handles special characters !@#$%^&*()\" do\n # test\n end\n\n it \"handles multiline\n string names\" do\n # test\n end\n\n it do\n # one-liner with empty name block\n end\nend" +- name: run + line: 251 + column: 1 + text: describe +- name: name + line: 251 + column: 11 + text: Edge cases +- name: RUBY_TEST_NAME + line: 251 + column: 11 + text: Edge cases +- name: _ruby-test + line: 252 + column: 3 + text: "it \"handles empty blocks\" do\n end" +- name: run + line: 252 + column: 3 + text: it +- name: name + line: 252 + column: 6 + text: "\"handles empty blocks\"" +- name: RUBY_TEST_NAME + line: 252 + column: 6 + text: "\"handles empty blocks\"" +- name: _ruby-test + line: 252 + column: 3 + text: "it \"handles empty blocks\" do\n end" +- name: run + line: 252 + column: 3 + text: it +- name: name + line: 252 + column: 7 + text: handles empty blocks +- name: RUBY_TEST_NAME + line: 252 + column: 7 + text: handles empty blocks +- name: _ruby-test + line: 255 + column: 3 + text: "it \"handles special characters !@#$%^&*()\" do\n # test\n end" +- name: run + line: 255 + column: 3 + text: it +- name: name + line: 255 + column: 6 + text: "\"handles special characters !@#$%^&*()\"" +- name: RUBY_TEST_NAME + line: 255 + column: 6 + text: "\"handles special characters !@#$%^&*()\"" +- name: _ruby-test + line: 255 + column: 3 + text: "it \"handles special characters !@#$%^&*()\" do\n # test\n end" +- name: run + line: 255 + column: 3 + text: it +- name: name + line: 255 + column: 7 + text: handles special characters !@ +- name: RUBY_TEST_NAME + line: 255 + column: 7 + text: handles special characters !@ +- name: _ruby-test + line: 255 + column: 3 + text: "it \"handles special characters !@#$%^&*()\" do\n # test\n end" +- name: run + line: 255 + column: 3 + text: it +- name: name + line: 255 + column: 36 + text: "#$%^&*()" +- name: RUBY_TEST_NAME + line: 255 + column: 36 + text: "#$%^&*()" +- name: _ruby-test + line: 259 + column: 3 + text: "it \"handles multiline\n string names\" do\n # test\n end" +- name: run + line: 259 + column: 3 + text: it +- name: name + line: 259 + column: 6 + text: "\"handles multiline\n string names\"" +- name: RUBY_TEST_NAME + line: 259 + column: 6 + text: "\"handles multiline\n string names\"" +- name: _ruby-test + line: 259 + column: 3 + text: "it \"handles multiline\n string names\" do\n # test\n end" +- name: run + line: 259 + column: 3 + text: it +- name: name + line: 259 + column: 7 + text: "handles multiline\n string names" +- name: RUBY_TEST_NAME + line: 259 + column: 7 + text: "handles multiline\n string names" +- name: _ruby-test + line: 264 + column: 3 + text: "it do\n # one-liner with empty name block\n end" +- name: run + line: 264 + column: 3 + text: it +- name: name + line: 264 + column: 6 + text: "do\n # one-liner with empty name block\n end" +- name: RUBY_TEST_NAME + line: 264 + column: 6 + text: "do\n # one-liner with empty name block\n end" +- name: _ruby-test + line: 269 + column: 1 + text: "class EmptyTest < Minitest::Test\n def test_empty\n end\nend" +- name: run + line: 269 + column: 7 + text: EmptyTest +- name: name + line: 269 + column: 7 + text: EmptyTest +- name: RUBY_TEST_NAME + line: 269 + column: 7 + text: EmptyTest +- name: superclass + line: 269 + column: 19 + text: "Minitest::Test" +- name: _ruby-test + line: 270 + column: 3 + text: "def test_empty\n end" +- name: run + line: 270 + column: 7 + text: test_empty +- name: name + line: 270 + column: 7 + text: test_empty +- name: RUBY_TEST_NAME + line: 270 + column: 7 + text: test_empty diff --git a/tests/languages/ruby/snapshots/textobjects.snap b/tests/languages/ruby/snapshots/textobjects.snap new file mode 100644 index 0000000..ad1a020 --- /dev/null +++ b/tests/languages/ruby/snapshots/textobjects.snap @@ -0,0 +1,68 @@ +--- +source: tests/ruby.rs +expression: captures +--- +- name: comment.inside + line: 1 + column: 1 + text: "# Comment line for textobjects" +- name: class.around + line: 3 + column: 1 + text: "class Widget\n def initialize\n # instance method\n end\n\n def self.build\n new\n end\n\n class << self\n def singleton_block\n # singleton class body\n end\n end\nend" +- name: class.inside + line: 4 + column: 3 + text: "def initialize\n # instance method\n end\n\n def self.build\n new\n end\n\n class << self\n def singleton_block\n # singleton class body\n end\n end" +- name: comment.inside + line: 5 + column: 5 + text: "# instance method" +- name: function.around + line: 4 + column: 3 + text: "def initialize\n # instance method\n end" +- name: function.around + line: 8 + column: 3 + text: "def self.build\n new\n end" +- name: function.inside + line: 9 + column: 5 + text: new +- name: comment.inside + line: 14 + column: 7 + text: "# singleton class body" +- name: function.around + line: 13 + column: 5 + text: "def singleton_block\n # singleton class body\n end" +- name: class.around + line: 12 + column: 3 + text: "class << self\n def singleton_block\n # singleton class body\n end\n end" +- name: class.inside + line: 13 + column: 5 + text: "def singleton_block\n # singleton class body\n end" +- name: comment.inside + line: 20 + column: 3 + text: "# module comment" +- name: class.around + line: 19 + column: 1 + text: "module Tools\n # module comment\n def self.helper\n # helper\n end\nend" +- name: class.inside + line: 21 + column: 3 + text: "def self.helper\n # helper\n end" +- name: comment.inside + line: 22 + column: 5 + text: "# helper" +- name: function.around + line: 21 + column: 3 + text: "def self.helper\n # helper\n end" diff --git a/tests/languages/ruby/textobjects.rb b/tests/languages/ruby/textobjects.rb new file mode 100644 index 0000000..a9d592b --- /dev/null +++ b/tests/languages/ruby/textobjects.rb @@ -0,0 +1,24 @@ +# Comment line for textobjects + +class Widget + def initialize + # instance method + end + + def self.build + new + end + + class << self + def singleton_block + # singleton class body + end + end +end + +module Tools + # module comment + def self.helper + # helper + end +end diff --git a/tests/ruby.rs b/tests/ruby.rs new file mode 100644 index 0000000..07e4a0b --- /dev/null +++ b/tests/ruby.rs @@ -0,0 +1,66 @@ +mod support; + +// ============================================================================ +// Runnables Tests +// ============================================================================ + +#[test] +fn runnables() { + support::assert_query_snapshot( + "runnables", + "tests/languages/ruby/runnables.rb", + "languages/ruby/runnables.scm", + ); +} + +// ============================================================================ +// Debugger Tests +// ============================================================================ + +#[test] +fn debugger() { + support::assert_query_snapshot( + "debugger", + "tests/languages/ruby/debugger.rb", + "languages/ruby/debugger.scm", + ); +} + +// ============================================================================ +// Outline Tests +// ============================================================================ + +#[test] +fn outline() { + support::assert_query_snapshot( + "outline", + "tests/languages/ruby/outline.rb", + "languages/ruby/outline.scm", + ); +} + +// ============================================================================ +// Textobjects Tests +// ============================================================================ + +#[test] +fn textobjects() { + support::assert_query_snapshot( + "textobjects", + "tests/languages/ruby/textobjects.rb", + "languages/ruby/textobjects.scm", + ); +} + +// ============================================================================ +// Injections Tests +// ============================================================================ + +#[test] +fn injections() { + support::assert_query_snapshot( + "injections", + "tests/languages/ruby/injections.rb", + "languages/ruby/injections.scm", + ); +} diff --git a/tests/support/mod.rs b/tests/support/mod.rs new file mode 100644 index 0000000..ee04155 --- /dev/null +++ b/tests/support/mod.rs @@ -0,0 +1,151 @@ +use streaming_iterator::StreamingIterator; +use std::path::Path; +use tree_sitter::{Parser, Query, QueryCursor}; + +/// Represents a single capture from a query match +#[derive(Debug, serde::Serialize)] +pub struct Capture { + pub name: String, + pub line: usize, + pub column: usize, + pub text: String, +} + +fn normalize_line_endings(text: &str) -> String { + text.replace("\r\n", "\n").replace('\r', "\n") +} + +/// Run a tree-sitter query on source code and return captures +fn language_for_id(language_id: &str) -> tree_sitter::Language { + match language_id { + "ruby" => tree_sitter_ruby::LANGUAGE.into(), + _ => panic!("Unsupported language id for query tests: {language_id}"), + } +} + +fn extract_language_id(path: &str, root: &str) -> Option { + let normalized = path.replace('\\', "/"); + let mut iter = Path::new(&normalized) + .components() + .map(|component| component.as_os_str()); + while let Some(component) = iter.next() { + if component == root { + return iter + .next() + .map(|segment| segment.to_string_lossy().into_owned()); + } + } + None +} + +pub fn detect_language_id(fixture_path: &str, query_path: &str) -> String { + let fixture_lang = extract_language_id(fixture_path, "languages"); + let query_lang = extract_language_id(query_path, "languages"); + + match (fixture_lang, query_lang) { + (Some(fixture_lang), Some(query_lang)) if fixture_lang == query_lang => fixture_lang, + (Some(fixture_lang), Some(query_lang)) => { + panic!("Mismatched language ids: {fixture_lang} vs {query_lang}") + } + (Some(fixture_lang), None) => fixture_lang, + (None, Some(query_lang)) => query_lang, + (None, None) => { + panic!("Unable to detect language id from paths: {fixture_path}, {query_path}") + } + } +} + +pub fn run_query(source: &str, query_source: &str, language_id: &str) -> Vec { + let mut parser = Parser::new(); + let language = language_for_id(language_id); + parser + .set_language(&language) + .unwrap_or_else(|_| panic!("Error loading {language_id} parser")); + + let tree = parser.parse(source, None).expect("Failed to parse source"); + let query = Query::new(&language, query_source).expect("Failed to create query"); + + let mut cursor = QueryCursor::new(); + let mut captures = Vec::new(); + let source_bytes = source.as_bytes(); + + let mut matches = cursor.matches(&query, tree.root_node(), source_bytes); + while let Some(match_) = matches.next() { + for capture in match_.captures { + let capture_name = &query.capture_names()[capture.index as usize]; + let node = capture.node; + let start = node.start_position(); + let text = node + .utf8_text(source_bytes) + .expect("Failed to extract capture text"); + + captures.push(Capture { + name: capture_name.to_string(), + line: start.row + 1, + column: start.column + 1, + text: text.to_string(), + }); + } + } + + captures +} + +pub fn snapshot_settings(language_id: &str) -> insta::Settings { + let snapshot_dir = Path::new(env!("CARGO_MANIFEST_DIR")) + .join("tests") + .join("languages") + .join(language_id) + .join("snapshots"); + std::fs::create_dir_all(&snapshot_dir).expect("Failed to create snapshot directory"); + + let mut settings = insta::Settings::clone_current(); + settings.set_snapshot_path(snapshot_dir); + settings.set_prepend_module_to_snapshot(false); + settings +} + +pub fn assert_query_snapshot(snapshot_name: &str, fixture_path: &str, query_path: &str) { + let fixture_abs = Path::new(env!("CARGO_MANIFEST_DIR")).join(fixture_path); + let query_abs = Path::new(env!("CARGO_MANIFEST_DIR")).join(query_path); + let source = std::fs::read_to_string(&fixture_abs).unwrap_or_else(|error| { + panic!( + "Failed to read query fixture file {}: {error}", + fixture_abs.display() + ) + }); + let query_source = std::fs::read_to_string(&query_abs).unwrap_or_else(|error| { + panic!("Failed to read query file {}: {error}", query_abs.display()) + }); + let language_id = detect_language_id(fixture_path, query_path); + let captures = run_query( + &normalize_line_endings(&source), + &normalize_line_endings(&query_source), + &language_id, + ); + let settings = snapshot_settings(&language_id); + settings.bind(|| insta::assert_yaml_snapshot!(snapshot_name, captures)); +} + +#[cfg(test)] +mod tests { + use super::detect_language_id; + + #[test] + fn detects_language_from_fixture_path() { + let language = detect_language_id( + "tests/languages/ruby/runnables.rb", + "languages/ruby/runnables.scm", + ); + assert_eq!(language, "ruby"); + } + + #[test] + fn detects_language_with_windows_separators() { + let language = detect_language_id( + "tests\\languages\\erb\\fixtures.rb", + "languages\\erb\\runnables.scm", + ); + assert_eq!(language, "erb"); + } +} From 03ac57e8dc9381376fcea4962dda0a3269b976e0 Mon Sep 17 00:00:00 2001 From: Vitaly Slobodin Date: Sat, 24 Jan 2026 23:49:50 +0100 Subject: [PATCH 2/4] test(erb): Add tree-sitter tests for ERB --- Cargo.lock | 10 ++++ Cargo.toml | 1 + tests/erb.rs | 10 ++++ tests/languages/erb/injections.erb | 7 +++ tests/languages/erb/snapshots/injections.snap | 48 +++++++++++++++++++ tests/support/mod.rs | 1 + 6 files changed, 77 insertions(+) create mode 100644 tests/erb.rs create mode 100644 tests/languages/erb/injections.erb create mode 100644 tests/languages/erb/snapshots/injections.snap diff --git a/Cargo.lock b/Cargo.lock index 3789bc2..a90b793 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -762,6 +762,15 @@ dependencies = [ "tree-sitter-language", ] +[[package]] +name = "tree-sitter-embedded-template" +version = "0.25.0" +source = "git+https://github.com/tree-sitter/tree-sitter-embedded-template.git?rev=c70c1de07dedd532089c0c90835c8ed9fa694f5c#c70c1de07dedd532089c0c90835c8ed9fa694f5c" +dependencies = [ + "cc", + "tree-sitter-language", +] + [[package]] name = "tree-sitter-language" version = "0.1.6" @@ -1113,6 +1122,7 @@ dependencies = [ "serde_json", "streaming-iterator", "tree-sitter", + "tree-sitter-embedded-template", "tree-sitter-ruby", "zed_extension_api", ] diff --git a/Cargo.toml b/Cargo.toml index 0d93a47..d61b441 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,5 +18,6 @@ zed_extension_api = "0.7.0" [dev-dependencies] tree-sitter = "0.25" tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "71bd32fb7607035768799732addba884a37a6210" } +tree-sitter-embedded-template = { git = "https://github.com/tree-sitter/tree-sitter-embedded-template.git", rev = "c70c1de07dedd532089c0c90835c8ed9fa694f5c" } insta = { version = "1.46", features = ["yaml"] } streaming-iterator = "0.1" diff --git a/tests/erb.rs b/tests/erb.rs new file mode 100644 index 0000000..f712183 --- /dev/null +++ b/tests/erb.rs @@ -0,0 +1,10 @@ +mod support; + +#[test] +fn injections() { + support::assert_query_snapshot( + "injections", + "tests/languages/erb/injections.erb", + "languages/erb/injections.scm", + ); +} diff --git a/tests/languages/erb/injections.erb b/tests/languages/erb/injections.erb new file mode 100644 index 0000000..7584915 --- /dev/null +++ b/tests/languages/erb/injections.erb @@ -0,0 +1,7 @@ +Hello <%= user.name %> + +<%# Embedded template comment %> + +<% if admin? %> + Welcome, <%= admin_name %> +<% end %> diff --git a/tests/languages/erb/snapshots/injections.snap b/tests/languages/erb/snapshots/injections.snap new file mode 100644 index 0000000..bd9e9b3 --- /dev/null +++ b/tests/languages/erb/snapshots/injections.snap @@ -0,0 +1,48 @@ +--- +source: tests/ruby.rs +expression: captures +--- +- name: content + line: 1 + column: 1 + text: "Hello " +- name: content + line: 1 + column: 10 + text: " user.name " +- name: content + line: 1 + column: 23 + text: "\n\n" +- name: content + line: 3 + column: 4 + text: " Embedded template comment " +- name: content + line: 3 + column: 33 + text: "\n\n" +- name: content + line: 5 + column: 3 + text: " if admin? " +- name: content + line: 5 + column: 16 + text: "\n Welcome, " +- name: content + line: 6 + column: 15 + text: " admin_name " +- name: content + line: 6 + column: 29 + text: "\n" +- name: content + line: 7 + column: 3 + text: " end " +- name: content + line: 7 + column: 10 + text: "\n" diff --git a/tests/support/mod.rs b/tests/support/mod.rs index ee04155..f4c3c1d 100644 --- a/tests/support/mod.rs +++ b/tests/support/mod.rs @@ -19,6 +19,7 @@ fn normalize_line_endings(text: &str) -> String { fn language_for_id(language_id: &str) -> tree_sitter::Language { match language_id { "ruby" => tree_sitter_ruby::LANGUAGE.into(), + "erb" => tree_sitter_embedded_template::LANGUAGE.into(), _ => panic!("Unsupported language id for query tests: {language_id}"), } } From fcb2e3f25cb02795854d30befbc82386ccdb6258 Mon Sep 17 00:00:00 2001 From: Vitaly Slobodin Date: Sat, 24 Jan 2026 23:51:53 +0100 Subject: [PATCH 3/4] test: Use `streaming_iterator` from `tree-sitter` crate --- Cargo.lock | 1 - Cargo.toml | 1 - tests/support/mod.rs | 3 +-- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a90b793..bd65881 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1120,7 +1120,6 @@ dependencies = [ "regex", "serde", "serde_json", - "streaming-iterator", "tree-sitter", "tree-sitter-embedded-template", "tree-sitter-ruby", diff --git a/Cargo.toml b/Cargo.toml index d61b441..7424459 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,4 +20,3 @@ tree-sitter = "0.25" tree-sitter-ruby = { git = "https://github.com/tree-sitter/tree-sitter-ruby.git", rev = "71bd32fb7607035768799732addba884a37a6210" } tree-sitter-embedded-template = { git = "https://github.com/tree-sitter/tree-sitter-embedded-template.git", rev = "c70c1de07dedd532089c0c90835c8ed9fa694f5c" } insta = { version = "1.46", features = ["yaml"] } -streaming-iterator = "0.1" diff --git a/tests/support/mod.rs b/tests/support/mod.rs index f4c3c1d..3dbfaf0 100644 --- a/tests/support/mod.rs +++ b/tests/support/mod.rs @@ -1,6 +1,5 @@ -use streaming_iterator::StreamingIterator; use std::path::Path; -use tree_sitter::{Parser, Query, QueryCursor}; +use tree_sitter::{Parser, Query, QueryCursor, StreamingIterator}; /// Represents a single capture from a query match #[derive(Debug, serde::Serialize)] From 50a5f23eba56f8544b49a976c054a19e2a04690c Mon Sep 17 00:00:00 2001 From: Vitaly Slobodin Date: Sat, 24 Jan 2026 23:58:28 +0100 Subject: [PATCH 4/4] test: Mark snapshots as generated YAML --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dc9fdbd --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +tests/languages/**/snapshots/*.snap linguist-language=YAML