bashcov 3.3.0 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cfda1fc3d4c19c0782e856c20e9435b91e16487221fb97e2875b32a5cb73f653
4
- data.tar.gz: a226b0ec693237618d3a50c3454a23168aff12ed7aefd79a85a796201b059729
3
+ metadata.gz: f0747d5303e019390aac25da832f145d0fe434ca0990ce68b11124423f6cf1f7
4
+ data.tar.gz: daed283089aa39da826552a98178c59916e215e30552113ebf094103388cae5b
5
5
  SHA512:
6
- metadata.gz: b44520af7881af5f84965c74cb673451536edefb64556bde376e13597173e1126ff6873aad360d484aa8886262bd5ad8915588a299819b891b02331d9d4ae784
7
- data.tar.gz: df3e60d5fbfa4476b51265ae84314a41b28a592062cefa62bda00a20b3d336bc1ba66994c14092b9d24e175aed2be54643e966c97ad33844b6f3726ff1019d42
6
+ metadata.gz: 8e04f898757e9fd035eac7f5da81e5de7a93a2d492f3039a6c97c2b88610fcce1f86af7c3ddc734ae941f6cfcebe05361dfe442826f7dcf792d0d6cb9a88b542
7
+ data.tar.gz: 9446b060debec76ebb08765cb7c16b8c16bb1d17b50d85da3543631ab2c5c9c32671033bdfd9bd811cda0d735c454a2a2e803f30ad812aebb7ea253e7e8cc2d2
data/.rubocop.yml CHANGED
@@ -68,8 +68,11 @@ Style/StringLiterals:
68
68
  Style/SpecialGlobalVars:
69
69
  Enabled: false
70
70
 
71
+ Style/TrailingCommaInArguments:
72
+ EnforcedStyleForMultiline: consistent_comma
73
+
71
74
  Style/TrailingCommaInArrayLiteral:
72
- EnforcedStyleForMultiline: comma
75
+ EnforcedStyleForMultiline: consistent_comma
73
76
 
74
77
  Style/TrailingCommaInHashLiteral:
75
- EnforcedStyleForMultiline: comma
78
+ EnforcedStyleForMultiline: consistent_comma
data/.simplecov CHANGED
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- SimpleCov.start do
3
+ SimpleCov.configure do
4
4
  minimum_coverage 95
5
- add_filter "/features/"
6
- add_filter "/spec/"
7
- add_filter "/tmp/"
8
- add_filter "/.git/"
5
+ skip "/features/"
6
+ skip "/spec/"
7
+ skip "/tmp/"
8
+ skip "/.git/"
9
9
  end
data/CHANGELOG.md CHANGED
@@ -1,7 +1,42 @@
1
- ## Unreleased ([changes](https://github.com/infertux/bashcov/compare/v3.3.0...master))
1
+ ## Unreleased ([changes](https://github.com/infertux/bashcov/compare/v4.0.1...master))
2
2
 
3
3
  * TBD
4
4
 
5
+ ## v4.0.1, 2026-10-26 ([changes](https://github.com/infertux/bashcov/compare/v4.0.0...v4.0.1))
6
+
7
+ * [BUGFIX] Fix coverage of multiline strings on Bash < 5.3 (fixes #108)
8
+ * [BUGFIX] Fix coverage of multiline strings opened after a line continuation
9
+ * [BUGFIX] Handle escaped characters in multiline double-quoted strings
10
+ * [BUGFIX] Stop heredoc matches at the first closing delimiter
11
+ * [BUGFIX] Only allow tab-indented heredoc delimiters after `<<-`
12
+ * [BUGFIX] Recognize heredoc delimiters quoted with double quotes or a backslash
13
+ * [MISC] Speed up lexer on files with multiline constructs
14
+ * [MISC] Make sure we use compatible cucumber and aruba releases
15
+ * [MISC] Add link to Buy Me a Coffee
16
+
17
+ ## v4.0.0, 2026-08-25 ([changes](https://github.com/infertux/bashcov/compare/v3.3.0...v4.0.0))
18
+
19
+ * [BUGFIX] Fix build for Nix
20
+ * [MISC] Update Nix lockfile
21
+ * [MISC] Ignore .ruby-version file
22
+ * [FEATURE] Update coverage result to match SimpleCov new API
23
+ * [BUGFIX] Fix build for Bash 4.4
24
+ * [BUGFIX] Run Cucumber examples in random order
25
+ * [MISC] Test against all Ruby versions
26
+ * [MISC] Add screenshot to README
27
+ * [MISC] Run Cucumber against Bash 5.3
28
+ * [BUGFIX] Fix call to `find` command with zsh safeguard
29
+ * [BUGFIX] Fix deprecation warnings
30
+ * [MISC] Upgrade Ruby image for GitLab CI
31
+ * [FEATURE] - Upgrade simplecov dependency
32
+ * [BUGFIX] Fix support for Bash 5.3
33
+ * [MISC] Enforce consistent commas with Rubocop
34
+ * [BUGFIX] Make sure StringScanner is always loaded
35
+ * [BUGFIX] Use reliable Bash mirror
36
+ * [BUGFIX] Fix GitHub Action
37
+ * [BUGFIX] Fix Rubocop violation
38
+ * [BUGFIX] Fix deprecation warning for actions/checkout
39
+
5
40
  ## v3.3.0, 2026-02-18 ([changes](https://github.com/infertux/bashcov/compare/v3.2.0...v3.3.0))
6
41
 
7
42
  * [MISC] Add workflow to build Gem
data/Gemfile.nix.lock CHANGED
@@ -1,89 +1,91 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bashcov (3.2.0)
5
- simplecov (~> 0.21)
4
+ bashcov (4.0.1)
5
+ simplecov (~> 1.1)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- aruba (2.3.3)
10
+ aruba (2.4.1)
11
11
  bundler (>= 1.17)
12
12
  contracts (>= 0.16.0, < 0.18.0)
13
- cucumber (>= 8.0, < 11.0)
13
+ cucumber (>= 8.0, < 12.0)
14
+ irb (~> 1.16)
14
15
  rspec-expectations (>= 3.4, < 5.0)
15
16
  thor (~> 1.0)
16
17
  ast (2.4.3)
17
18
  base64 (0.3.0)
18
19
  benchmark (0.5.0)
19
- bigdecimal (4.0.1)
20
+ bigdecimal (4.1.3)
20
21
  builder (3.3.0)
21
22
  bundler-audit (0.9.3)
22
23
  bundler (>= 1.2.0)
23
24
  thor (~> 1.0)
24
25
  contracts (0.17.3)
25
- cucumber (10.2.0)
26
+ cucumber (11.1.1)
26
27
  base64 (~> 0.2)
27
28
  builder (~> 3.2)
28
29
  cucumber-ci-environment (> 9, < 12)
29
- cucumber-core (> 15, < 17)
30
+ cucumber-core (>= 16.2.0, < 17)
30
31
  cucumber-cucumber-expressions (> 17, < 20)
31
- cucumber-html-formatter (> 21, < 23)
32
+ cucumber-html-formatter (> 21, < 24)
32
33
  diff-lcs (~> 1.5)
33
34
  logger (~> 1.6)
34
35
  mini_mime (~> 1.1)
35
36
  multi_test (~> 1.1)
36
- sys-uname (~> 1.3)
37
+ sys-uname (~> 1.5)
37
38
  cucumber-ci-environment (11.0.0)
38
- cucumber-core (16.1.1)
39
+ cucumber-core (16.2.0)
39
40
  cucumber-gherkin (> 36, < 40)
40
41
  cucumber-messages (> 31, < 33)
41
42
  cucumber-tag-expressions (> 6, < 9)
42
- cucumber-cucumber-expressions (18.0.1)
43
+ cucumber-cucumber-expressions (19.0.1)
43
44
  bigdecimal
44
- cucumber-gherkin (37.0.1)
45
- cucumber-messages (>= 31, < 32)
46
- cucumber-html-formatter (22.3.0)
45
+ cucumber-gherkin (39.1.0)
46
+ cucumber-messages (>= 31, < 33)
47
+ cucumber-html-formatter (23.1.0)
47
48
  cucumber-messages (> 23, < 33)
48
- cucumber-messages (31.1.0)
49
+ cucumber-messages (32.3.1)
49
50
  cucumber-tag-expressions (8.1.0)
50
- date (3.5.1)
51
51
  diff-lcs (1.6.2)
52
- docile (1.4.1)
53
- erb (6.0.1)
52
+ erb (6.0.7)
54
53
  ffi (1.16.3)
55
- io-console (0.8.2)
56
- irb (1.16.0)
54
+ io-console (0.9.4)
55
+ irb (1.18.0)
57
56
  pp (>= 0.6.0)
57
+ prism (>= 1.3.0)
58
58
  rdoc (>= 4.0.0)
59
59
  reline (>= 0.4.2)
60
- json (2.18.0)
61
- language_server-protocol (3.17.0.5)
60
+ json (3.1.0)
61
+ language_server-protocol (3.17.0.6)
62
62
  lint_roller (1.1.0)
63
63
  logger (1.7.0)
64
64
  memoist3 (1.0.0)
65
65
  mini_mime (1.1.5)
66
66
  multi_test (1.1.0)
67
- parallel (1.27.0)
68
- parser (3.3.10.0)
67
+ parallel (2.3.0)
68
+ parser (3.3.12.0)
69
69
  ast (~> 2.4.1)
70
70
  racc
71
- pp (0.6.3)
71
+ pp (0.6.4)
72
72
  prettyprint
73
- prettyprint (0.2.0)
74
- prism (1.7.0)
75
- psych (5.3.1)
76
- date
77
- stringio
73
+ prettyprint (0.2.1)
74
+ prism (1.9.0)
78
75
  racc (1.8.1)
79
76
  rainbow (3.1.1)
80
- rake (13.3.1)
81
- rdoc (7.0.3)
77
+ rake (13.4.2)
78
+ rbs (4.2.0)
79
+ logger
80
+ prism (>= 1.6.0)
81
+ tsort
82
+ rdoc (8.1.0)
82
83
  erb
83
- psych (>= 4.0.0)
84
+ prism (>= 1.6.0)
85
+ rbs (>= 4.0.0)
84
86
  tsort
85
- regexp_parser (2.11.3)
86
- reline (0.6.3)
87
+ regexp_parser (2.13.1)
88
+ reline (0.7.0)
87
89
  io-console (~> 0.5)
88
90
  rspec (3.13.2)
89
91
  rspec-core (~> 3.13.0)
@@ -94,47 +96,42 @@ GEM
94
96
  rspec-expectations (3.13.5)
95
97
  diff-lcs (>= 1.2.0, < 2.0)
96
98
  rspec-support (~> 3.13.0)
97
- rspec-mocks (3.13.7)
99
+ rspec-mocks (3.13.8)
98
100
  diff-lcs (>= 1.2.0, < 2.0)
99
101
  rspec-support (~> 3.13.0)
100
- rspec-support (3.13.6)
101
- rubocop (1.82.1)
102
- json (~> 2.3)
102
+ rspec-support (3.13.7)
103
+ rubocop (1.92.0)
104
+ json (>= 2.3)
103
105
  language_server-protocol (~> 3.17.0.2)
104
106
  lint_roller (~> 1.1.0)
105
- parallel (~> 1.10)
107
+ parallel (>= 1.10)
106
108
  parser (>= 3.3.0.2)
107
109
  rainbow (>= 2.2.2, < 4.0)
108
- regexp_parser (>= 2.9.3, < 3.0)
109
- rubocop-ast (>= 1.48.0, < 2.0)
110
+ regexp_parser (>= 2.11.3, < 3.0)
111
+ rubocop-ast (>= 1.49.0, < 2.0)
110
112
  ruby-progressbar (~> 1.7)
111
113
  unicode-display_width (>= 2.4.0, < 4.0)
112
- rubocop-ast (1.49.0)
114
+ rubocop-ast (1.50.0)
113
115
  parser (>= 3.3.7.2)
114
116
  prism (~> 1.7)
115
117
  rubocop-rake (0.7.1)
116
118
  lint_roller (~> 1.1)
117
119
  rubocop (>= 1.72.1)
118
- rubocop-rspec (3.8.0)
120
+ rubocop-rspec (3.10.2)
119
121
  lint_roller (~> 1.1)
120
- rubocop (~> 1.81)
122
+ regexp_parser (>= 2.0)
123
+ rubocop (~> 1.86, >= 1.86.2)
121
124
  ruby-progressbar (1.13.0)
122
- simplecov (0.22.0)
123
- docile (~> 1.1)
124
- simplecov-html (~> 0.11)
125
- simplecov_json_formatter (~> 0.1)
126
- simplecov-html (0.13.2)
127
- simplecov_json_formatter (0.1.4)
128
- stringio (3.2.0)
129
- sys-uname (1.4.1)
125
+ simplecov (1.3.2)
126
+ sys-uname (1.5.1)
130
127
  ffi (~> 1.1)
131
128
  memoist3 (~> 1.0.0)
132
- thor (1.4.0)
129
+ thor (1.5.0)
133
130
  tsort (0.2.0)
134
- unicode-display_width (3.2.0)
135
- unicode-emoji (~> 4.1)
136
- unicode-emoji (4.2.0)
137
- yard (0.9.38)
131
+ unicode-display_width (3.3.0)
132
+ unicode-emoji (~> 4.3)
133
+ unicode-emoji (4.3.0)
134
+ yard (0.9.45)
138
135
 
139
136
  PLATFORMS
140
137
  aarch64-linux-gnu
@@ -150,11 +147,11 @@ PLATFORMS
150
147
  x86_64-linux-musl
151
148
 
152
149
  DEPENDENCIES
153
- aruba
150
+ aruba (~> 2.4.1)
154
151
  bashcov!
155
152
  benchmark
156
153
  bundler-audit
157
- cucumber
154
+ cucumber (~> 11.1.1)
158
155
  ffi (~> 1.16.0)
159
156
  irb
160
157
  rake
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  # Bashcov
2
2
 
3
+ [![Buy Me a Coffee](https://img.shields.io/badge/buy%20me%20a%20coffee-donate-yellow.svg)](https://buymeacoffee.com/infertux)
3
4
  [![Funding](https://img.shields.io/liberapay/patrons/infertux.svg?logo=liberapay)](https://liberapay.com/infertux/donate)
4
5
  [![Gem Version](https://img.shields.io/gem/v/bashcov.svg)](https://rubygems.org/gems/bashcov)
5
6
  [![Build Status](https://github.com/infertux/bashcov/actions/workflows/ci.yml/badge.svg)](https://github.com/infertux/bashcov/actions/workflows/ci.yml)
@@ -21,10 +22,6 @@ so your report includes coverage across your test suites and thereby gives you a
21
22
  It uses the [SimpleCov](https://github.com/colszowka/simplecov) coverage library to generate HTML reports.
22
23
  SimpleCov gets installed automatically when you install Bashcov.
23
24
 
24
- Here are example coverages generated by Bashcov:
25
- [test app demo](https://infertux.github.io/bashcov/test_app/ "Coverage for the bundled test application") &
26
- [RVM demo](https://infertux.github.io/bashcov/rvm/ "Coverage for RVM").
27
-
28
25
  ## Installation
29
26
 
30
27
  `gem install bashcov`
@@ -46,6 +43,8 @@ For more information, including other installation methods, see [`INSTALL.md`](.
46
43
 
47
44
  It will create a directory named `./coverage/`, you may open `./coverage/index.html` to browse the coverage report.
48
45
 
46
+ ![Screenshot](screenshot.png)
47
+
49
48
  ### SimpleCov integration
50
49
 
51
50
  You can leverage the underlying library [SimpleCov](https://github.com/colszowka/simplecov)
@@ -61,7 +60,7 @@ For development tips, see [the hacking guide](./HACKING.md).
61
60
 
62
61
  ## Sponsorship
63
62
 
64
- Bashcov was [created in 2012](https://github.com/infertux/bashcov/commit/f65e65e5aa3377beb334beee9924136a34a913e8) and it needs your help. I have been maintaining the project for over a decade and keeping it working with new releases of Bash and Ruby takes time. If you use Bashcov professionally, please consider supporting it on [Liberapay](https://liberapay.com/infertux) through your employer or directly. Thank you for supporting *Free and Open-Source Software*.
63
+ Bashcov was [created in 2012](https://github.com/infertux/bashcov/commit/f65e65e5aa3377beb334beee9924136a34a913e8) and it needs your help. I have been maintaining the project for over a decade and keeping it working with new releases of Bash and Ruby takes time. If you use Bashcov professionally, please consider supporting it on [Buy Me a Coffee](https://buymeacoffee.com/infertux) or [Liberapay](https://liberapay.com/infertux) through your employer or directly. Thank you for supporting *Free and Open-Source Software*.
65
64
 
66
65
  ## License
67
66
 
data/Rakefile CHANGED
@@ -7,15 +7,15 @@ Bundler::Audit::Task.new
7
7
 
8
8
  require "cucumber/rake/task"
9
9
  Cucumber::Rake::Task.new do |t|
10
- t.cucumber_opts = %w[--publish-quiet]
10
+ t.cucumber_opts = %w[--publish-quiet --backtrace --verbose --order=random]
11
11
  end
12
12
 
13
13
  require "rspec/core/rake_task"
14
- RSpec::Core::RakeTask.new(:spec) do |t|
14
+ RSpec::Core::RakeTask.new(:rspec) do |t|
15
15
  t.ruby_opts = "-w"
16
16
  end
17
17
 
18
18
  require "rubocop/rake_task"
19
19
  RuboCop::RakeTask.new
20
20
 
21
- task default: %i[bundle:audit cucumber spec rubocop]
21
+ task default: %i[bundle:audit cucumber rspec rubocop]
data/TESTING.md CHANGED
@@ -1,4 +1,3 @@
1
1
  `bundle exec rake` will run a quick test suite with the current Bash and Ruby version.
2
2
 
3
- `./test.sh` will run all [GitLab CI pipelines](https://gitlab.com/infertux/bashcov/-/pipelines) locally.
4
- You'll need [Docker](https://www.docker.com/) and [GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner) installed on your machine.
3
+ The full test suite runs on [GitHub](https://github.com/infertux/bashcov/actions).
data/bin/bashcov CHANGED
@@ -22,7 +22,7 @@ SimpleCov.command_name Bashcov.command_name
22
22
  SimpleCov.root Bashcov.root_directory
23
23
 
24
24
  result = SimpleCov::Result.new(coverage)
25
- if SimpleCov.use_merging
25
+ if SimpleCov.merging
26
26
  SimpleCov::ResultMerger.store_result(result)
27
27
  result = SimpleCov::ResultMerger.merged_result
28
28
  end
data/flake.nix CHANGED
@@ -172,7 +172,7 @@
172
172
  propagatedBuildInputs = [gems'];
173
173
 
174
174
  checkPhase = ''
175
- ${config.packages.gems.wrappedRuby}/bin/rake cucumber spec
175
+ ${config.packages.gems.wrappedRuby}/bin/rake cucumber rspec
176
176
  '';
177
177
 
178
178
  # Replace shebangs like "#!/usr/bin/env bash" with Nix store
@@ -206,7 +206,7 @@
206
206
  pname = "bashcov";
207
207
  gemdir = self;
208
208
  lockfile = ./Gemfile.nix.lock;
209
- version = "3.0.2";
209
+ version = "4.0.1";
210
210
  postBuild = ''
211
211
  for gem in $out/${ruby.gemPath}/bundler/gems/*; do
212
212
  ln -sfrT "$gem" $out/${ruby.gemPath}/gems/"''${gem##*/}"
data/gemset.nix CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  aruba = {
3
- dependencies = ["contracts" "cucumber" "rspec-expectations" "thor"];
3
+ dependencies = ["contracts" "cucumber" "irb" "rspec-expectations" "thor"];
4
4
  groups = ["development"];
5
5
  platforms = [];
6
6
  source = {
7
7
  remotes = ["https://rubygems.org"];
8
- sha256 = "1m7ijdx5zz5mizymmwxkydyszfcafgljgqlvmlw5m9v86c12yyl3";
8
+ sha256 = "03dg1hg58733rv2jl220pckal3vqqiqkjmfgnd9wknbb2d4ik0n6";
9
9
  type = "gem";
10
10
  };
11
- version = "2.3.3";
11
+ version = "2.4.1";
12
12
  };
13
13
  ast = {
14
14
  groups = ["default" "development"];
@@ -38,7 +38,7 @@
38
38
  path = ./.;
39
39
  type = "path";
40
40
  };
41
- version = "3.2.0";
41
+ version = "4.0.1";
42
42
  };
43
43
  benchmark = {
44
44
  groups = ["development"];
@@ -55,10 +55,10 @@
55
55
  platforms = [];
56
56
  source = {
57
57
  remotes = ["https://rubygems.org"];
58
- sha256 = "19y406nx17arzsbc515mjmr6k5p59afprspa1k423yd9cp8d61wb";
58
+ sha256 = "0rng45p4vc3f6nac44cnylwch7rj4zsff3icdz6c7garwpjy3sv1";
59
59
  type = "gem";
60
60
  };
61
- version = "4.0.1";
61
+ version = "4.1.3";
62
62
  };
63
63
  builder = {
64
64
  groups = ["default" "development"];
@@ -97,10 +97,10 @@
97
97
  platforms = [];
98
98
  source = {
99
99
  remotes = ["https://rubygems.org"];
100
- sha256 = "0n41b80fg8bz49m9rhms1g1zai2wl4m3z1841yv5h27lxhqvvvgx";
100
+ sha256 = "1i2favw0kk9pdikcwpqz0pl1p95g44r0rd8kiiwsyl2bl7s49pfy";
101
101
  type = "gem";
102
102
  };
103
- version = "10.2.0";
103
+ version = "11.1.1";
104
104
  };
105
105
  cucumber-ci-environment = {
106
106
  groups = ["default" "development"];
@@ -118,10 +118,10 @@
118
118
  platforms = [];
119
119
  source = {
120
120
  remotes = ["https://rubygems.org"];
121
- sha256 = "12bbwa5fzi08jspvk4wr17wmlrwz2abg87m2y5imz1p23q5aiank";
121
+ sha256 = "02wprwvf2f3ffzvbrzv8clxvm11p6s7gcjd3wpwfwbzlbjlmhasr";
122
122
  type = "gem";
123
123
  };
124
- version = "16.1.1";
124
+ version = "16.2.0";
125
125
  };
126
126
  cucumber-cucumber-expressions = {
127
127
  dependencies = ["bigdecimal"];
@@ -129,10 +129,10 @@
129
129
  platforms = [];
130
130
  source = {
131
131
  remotes = ["https://rubygems.org"];
132
- sha256 = "1rg3dcg2mapay1xbs8cybds05swmj8q9li8ynvrkzwvacfzs1643";
132
+ sha256 = "133cwgclgrphlws6l23sssgmjj41ckhldbwpny7q238r8n8c13k4";
133
133
  type = "gem";
134
134
  };
135
- version = "18.0.1";
135
+ version = "19.0.1";
136
136
  };
137
137
  cucumber-gherkin = {
138
138
  dependencies = ["cucumber-messages"];
@@ -140,10 +140,10 @@
140
140
  platforms = [];
141
141
  source = {
142
142
  remotes = ["https://rubygems.org"];
143
- sha256 = "1nankcfqfj3l4d3hkh4476fywjygjjk04n78jxzxnv59vjh7nhq6";
143
+ sha256 = "1vbrnf0j3pq162ccrm349mgm4x90lz0k69h11bc671axjl62mldf";
144
144
  type = "gem";
145
145
  };
146
- version = "37.0.1";
146
+ version = "39.1.0";
147
147
  };
148
148
  cucumber-html-formatter = {
149
149
  dependencies = ["cucumber-messages"];
@@ -151,20 +151,20 @@
151
151
  platforms = [];
152
152
  source = {
153
153
  remotes = ["https://rubygems.org"];
154
- sha256 = "0a873ll5305g8gbp4sbf4006pn4bck6c491qbwxdgnw8ap88wxpr";
154
+ sha256 = "1pwcvpfawpkdqw9fgdvk8i8n2k6glmmbdbh4jr5kjxn8jakv92bp";
155
155
  type = "gem";
156
156
  };
157
- version = "22.3.0";
157
+ version = "23.1.0";
158
158
  };
159
159
  cucumber-messages = {
160
160
  groups = ["default" "development"];
161
161
  platforms = [];
162
162
  source = {
163
163
  remotes = ["https://rubygems.org"];
164
- sha256 = "02jscha3irpflhl5aanjxgj6cqx198pl89zd162sdsc90f449r4i";
164
+ sha256 = "073phbyiblkp8sh4r2ss8gxa48gjlsj94nq00rnbkbzp3i68xj6x";
165
165
  type = "gem";
166
166
  };
167
- version = "31.1.0";
167
+ version = "32.3.1";
168
168
  };
169
169
  cucumber-tag-expressions = {
170
170
  groups = ["default" "development"];
@@ -176,16 +176,6 @@
176
176
  };
177
177
  version = "8.1.0";
178
178
  };
179
- date = {
180
- groups = ["default" "development"];
181
- platforms = [];
182
- source = {
183
- remotes = ["https://rubygems.org"];
184
- sha256 = "1h0db8r2v5llxdbzkzyllkfniqw9gm092qn7cbaib73v9lw0c3bm";
185
- type = "gem";
186
- };
187
- version = "3.5.1";
188
- };
189
179
  diff-lcs = {
190
180
  groups = ["default" "development"];
191
181
  platforms = [];
@@ -196,25 +186,15 @@
196
186
  };
197
187
  version = "1.6.2";
198
188
  };
199
- docile = {
200
- groups = ["default"];
201
- platforms = [];
202
- source = {
203
- remotes = ["https://rubygems.org"];
204
- sha256 = "07pj4z3h8wk4fgdn6s62vw1lwvhj0ac0x10vfbdkr9xzk7krn5cn";
205
- type = "gem";
206
- };
207
- version = "1.4.1";
208
- };
209
189
  erb = {
210
190
  groups = ["default" "development"];
211
191
  platforms = [];
212
192
  source = {
213
193
  remotes = ["https://rubygems.org"];
214
- sha256 = "1rcpq49pyaiclpjp3c3qjl25r95hqvin2q2dczaynaj7qncxvv18";
194
+ sha256 = "14pfj6zn0p1hxj6s6s0r7d424wap8zl9zxf89nj79y8fbg16vjn5";
215
195
  type = "gem";
216
196
  };
217
- version = "6.0.1";
197
+ version = "6.0.7";
218
198
  };
219
199
  ffi = {
220
200
  groups = ["development"];
@@ -231,41 +211,41 @@
231
211
  platforms = [];
232
212
  source = {
233
213
  remotes = ["https://rubygems.org"];
234
- sha256 = "1k0lk3pwadm2myvpg893n8jshmrf2sigrd4ki15lymy7gixaxqyn";
214
+ sha256 = "1cgvhm0d4awr8j42b8v1nl1jfgx45ihv8mylargfi3lj697k00x4";
235
215
  type = "gem";
236
216
  };
237
- version = "0.8.2";
217
+ version = "0.9.4";
238
218
  };
239
219
  irb = {
240
- dependencies = ["pp" "rdoc" "reline"];
220
+ dependencies = ["pp" "prism" "rdoc" "reline"];
241
221
  groups = ["development"];
242
222
  platforms = [];
243
223
  source = {
244
224
  remotes = ["https://rubygems.org"];
245
- sha256 = "01h8bdksg0cr8bw5dhlhr29ix33rp822jmshy6rdqz4lmk4mdgia";
225
+ sha256 = "1qs8a9vprg7s8krgq4s0pygr91hclqqyz98ik15p0m1sf2h5956y";
246
226
  type = "gem";
247
227
  };
248
- version = "1.16.0";
228
+ version = "1.18.0";
249
229
  };
250
230
  json = {
251
231
  groups = ["default" "development"];
252
232
  platforms = [];
253
233
  source = {
254
234
  remotes = ["https://rubygems.org"];
255
- sha256 = "01fmiz052cvnxgdnhb3qwcy88xbv7l3liz0fkvs5qgqqwjp0c1di";
235
+ sha256 = "1n1v9rhb19cnf1a89s6yvvhw394jy8qnqx9sg8bn12g5zpwcrrrw";
256
236
  type = "gem";
257
237
  };
258
- version = "2.18.0";
238
+ version = "3.1.0";
259
239
  };
260
240
  language_server-protocol = {
261
241
  groups = ["default" "development"];
262
242
  platforms = [];
263
243
  source = {
264
244
  remotes = ["https://rubygems.org"];
265
- sha256 = "1k0311vah76kg5m6zr7wmkwyk5p2f9d9hyckjpn3xgr83ajkj7px";
245
+ sha256 = "1w5p8c2145lmqzr25bxh4ikzjm6k8y1k5lriqqdpw9pq730w1wjy";
266
246
  type = "gem";
267
247
  };
268
- version = "3.17.0.5";
248
+ version = "3.17.0.6";
269
249
  };
270
250
  lint_roller = {
271
251
  groups = ["default" "development"];
@@ -322,10 +302,10 @@
322
302
  platforms = [];
323
303
  source = {
324
304
  remotes = ["https://rubygems.org"];
325
- sha256 = "0c719bfgcszqvk9z47w2p8j2wkz5y35k48ywwas5yxbbh3hm3haa";
305
+ sha256 = "0vvs2sar7wnw70j1jc1kv1k23m5grc0ci3bbrcf6mkh18683wnpp";
326
306
  type = "gem";
327
307
  };
328
- version = "1.27.0";
308
+ version = "2.3.0";
329
309
  };
330
310
  parser = {
331
311
  dependencies = ["ast" "racc"];
@@ -333,10 +313,10 @@
333
313
  platforms = [];
334
314
  source = {
335
315
  remotes = ["https://rubygems.org"];
336
- sha256 = "1mmb59323ldv6vxfmy98azgsla9k3di3fasvpb28hnn5bkx8fdff";
316
+ sha256 = "0a4q5h2hcihk79dbr20scgkm56l79qp7fsvfvkxlv8nmapvxg9i1";
337
317
  type = "gem";
338
318
  };
339
- version = "3.3.10.0";
319
+ version = "3.3.12.0";
340
320
  };
341
321
  pp = {
342
322
  dependencies = ["prettyprint"];
@@ -344,41 +324,30 @@
344
324
  platforms = [];
345
325
  source = {
346
326
  remotes = ["https://rubygems.org"];
347
- sha256 = "1xlxmg86k5kifci1xvlmgw56x88dmqf04zfzn7zcr4qb8ladal99";
327
+ sha256 = "0w5mha75hs8gdj75g8vl0sxpyp8rzvwq8a4jcmi4ah8cf370zjyz";
348
328
  type = "gem";
349
329
  };
350
- version = "0.6.3";
330
+ version = "0.6.4";
351
331
  };
352
332
  prettyprint = {
353
333
  groups = ["default" "development"];
354
334
  platforms = [];
355
335
  source = {
356
336
  remotes = ["https://rubygems.org"];
357
- sha256 = "14zicq3plqi217w6xahv7b8f7aj5kpxv1j1w98344ix9h5ay3j9b";
337
+ sha256 = "1m5pqkp8rdk0bkxxz3bp3vn8pn3bd9a97dkl8wfh1kyplrzdamfm";
358
338
  type = "gem";
359
339
  };
360
- version = "0.2.0";
340
+ version = "0.2.1";
361
341
  };
362
342
  prism = {
363
343
  groups = ["default" "development"];
364
344
  platforms = [];
365
345
  source = {
366
346
  remotes = ["https://rubygems.org"];
367
- sha256 = "00silqnlzzm97gn21lm39q95hjn058waqky44j25r67p9drjy1hh";
347
+ sha256 = "11ggfikcs1lv17nhmhqyyp6z8nq5pkfcj6a904047hljkxm0qlvv";
368
348
  type = "gem";
369
349
  };
370
- version = "1.7.0";
371
- };
372
- psych = {
373
- dependencies = ["date" "stringio"];
374
- groups = ["default" "development"];
375
- platforms = [];
376
- source = {
377
- remotes = ["https://rubygems.org"];
378
- sha256 = "0x0r3gc66abv8i4dw0x0370b5hrshjfp6kpp7wbp178cy775fypb";
379
- type = "gem";
380
- };
381
- version = "5.3.1";
350
+ version = "1.9.0";
382
351
  };
383
352
  racc = {
384
353
  groups = ["default" "development"];
@@ -405,31 +374,42 @@
405
374
  platforms = [];
406
375
  source = {
407
376
  remotes = ["https://rubygems.org"];
408
- sha256 = "175iisqb211n0qbfyqd8jz2g01q6xj038zjf4q0nm8k6kz88k7lc";
377
+ sha256 = "009p524zl0p0kfa65nii8wdmaigkmawv9pbvlcffky7islmmp0nb";
409
378
  type = "gem";
410
379
  };
411
- version = "13.3.1";
380
+ version = "13.4.2";
381
+ };
382
+ rbs = {
383
+ dependencies = ["logger" "prism" "tsort"];
384
+ groups = ["default" "development"];
385
+ platforms = [];
386
+ source = {
387
+ remotes = ["https://rubygems.org"];
388
+ sha256 = "0x067q8cdam4kv5dc09iq2nzca8qm2kdl0dr22gc0ny0vj3bixsi";
389
+ type = "gem";
390
+ };
391
+ version = "4.2.0";
412
392
  };
413
393
  rdoc = {
414
- dependencies = ["erb" "psych" "tsort"];
394
+ dependencies = ["erb" "prism" "rbs" "tsort"];
415
395
  groups = ["development"];
416
396
  platforms = [];
417
397
  source = {
418
398
  remotes = ["https://rubygems.org"];
419
- sha256 = "1yc1xa3wckwwan518qii22jagqzlr5bypflx3nkvpdqr3ncd1qyz";
399
+ sha256 = "02pn63i2r5z44hcfhxbaag9rvqsyznsliivnn7f3dzaw1a43gz5y";
420
400
  type = "gem";
421
401
  };
422
- version = "7.0.3";
402
+ version = "8.1.0";
423
403
  };
424
404
  regexp_parser = {
425
405
  groups = ["default" "development"];
426
406
  platforms = [];
427
407
  source = {
428
408
  remotes = ["https://rubygems.org"];
429
- sha256 = "192mzi0wgwl024pwpbfa6c2a2xlvbh3mjd75a0sakdvkl60z64ya";
409
+ sha256 = "0jxl6c5cagjz5i5n9jplhdy2izad6wapmwgfhqggb22nqfvvdvas";
430
410
  type = "gem";
431
411
  };
432
- version = "2.11.3";
412
+ version = "2.13.1";
433
413
  };
434
414
  reline = {
435
415
  dependencies = ["io-console"];
@@ -437,10 +417,10 @@
437
417
  platforms = [];
438
418
  source = {
439
419
  remotes = ["https://rubygems.org"];
440
- sha256 = "0d8q5c4nh2g9pp758kizh8sfrvngynrjlm0i1zn3cnsnfd4v160i";
420
+ sha256 = "0gaq2lc463ap1srz7y5kh2p4dxazs7vjrpiby58d9yfvan72s0av";
441
421
  type = "gem";
442
422
  };
443
- version = "0.6.3";
423
+ version = "0.7.0";
444
424
  };
445
425
  rspec = {
446
426
  dependencies = ["rspec-core" "rspec-expectations" "rspec-mocks"];
@@ -481,20 +461,20 @@
481
461
  platforms = [];
482
462
  source = {
483
463
  remotes = ["https://rubygems.org"];
484
- sha256 = "071bqrk2rblk3zq3jk1xxx0dr92y0szi5pxdm8waimxici706y89";
464
+ sha256 = "0iqxmw0knjiz5nf6pgr8ihs6cjzh89f0ppj3fqiz8cvms79x6sh8";
485
465
  type = "gem";
486
466
  };
487
- version = "3.13.7";
467
+ version = "3.13.8";
488
468
  };
489
469
  rspec-support = {
490
470
  groups = ["default" "development"];
491
471
  platforms = [];
492
472
  source = {
493
473
  remotes = ["https://rubygems.org"];
494
- sha256 = "1cmgz34hwj5s3jwxhyl8mszs24nci12ffbrmr5jb1si74iqf739f";
474
+ sha256 = "0z64h5rznm2zv21vjdjshz4v0h7bxvg02yc6g7yzxakj11byah06";
495
475
  type = "gem";
496
476
  };
497
- version = "3.13.6";
477
+ version = "3.13.7";
498
478
  };
499
479
  rubocop = {
500
480
  dependencies = ["json" "language_server-protocol" "lint_roller" "parallel" "parser" "rainbow" "regexp_parser" "rubocop-ast" "ruby-progressbar" "unicode-display_width"];
@@ -502,10 +482,10 @@
502
482
  platforms = [];
503
483
  source = {
504
484
  remotes = ["https://rubygems.org"];
505
- sha256 = "0wz2np5ck54vpwcz18y9x7w80c308wza7gmfcykysq59ajkadw89";
485
+ sha256 = "1q2nih91fjbv6j1qqxfhlc480zyhz94rniyh469vsw1fzd0q1xia";
506
486
  type = "gem";
507
487
  };
508
- version = "1.82.1";
488
+ version = "1.92.0";
509
489
  };
510
490
  rubocop-ast = {
511
491
  dependencies = ["parser" "prism"];
@@ -513,10 +493,10 @@
513
493
  platforms = [];
514
494
  source = {
515
495
  remotes = ["https://rubygems.org"];
516
- sha256 = "1zbikzd6237fvlzjfxdlhwi2vbmavg1cc81y6cyr581365nnghs9";
496
+ sha256 = "1nw84xk6vc2ls8sxqvyhxs2agh4l0jrws85d4bi3x0501lq8ijmr";
517
497
  type = "gem";
518
498
  };
519
- version = "1.49.0";
499
+ version = "1.50.0";
520
500
  };
521
501
  rubocop-rake = {
522
502
  dependencies = ["lint_roller" "rubocop"];
@@ -530,15 +510,15 @@
530
510
  version = "0.7.1";
531
511
  };
532
512
  rubocop-rspec = {
533
- dependencies = ["lint_roller" "rubocop"];
513
+ dependencies = ["lint_roller" "regexp_parser" "rubocop"];
534
514
  groups = ["development"];
535
515
  platforms = [];
536
516
  source = {
537
517
  remotes = ["https://rubygems.org"];
538
- sha256 = "0cxb9i1brf1cks8anv8mdj65n9rq6jyldyd1ij9sj8zjng60si18";
518
+ sha256 = "1qk5bx4vg7n17i9475h6dqkhay9m3s6vanq9y35hxl9cb762wghb";
539
519
  type = "gem";
540
520
  };
541
- version = "3.8.0";
521
+ version = "3.10.2";
542
522
  };
543
523
  ruby-progressbar = {
544
524
  groups = ["default" "development"];
@@ -551,45 +531,14 @@
551
531
  version = "1.13.0";
552
532
  };
553
533
  simplecov = {
554
- dependencies = ["docile" "simplecov-html" "simplecov_json_formatter"];
555
- groups = ["default"];
556
- platforms = [];
557
- source = {
558
- remotes = ["https://rubygems.org"];
559
- sha256 = "198kcbrjxhhzca19yrdcd6jjj9sb51aaic3b0sc3pwjghg3j49py";
560
- type = "gem";
561
- };
562
- version = "0.22.0";
563
- };
564
- simplecov-html = {
565
- groups = ["default"];
566
- platforms = [];
567
- source = {
568
- remotes = ["https://rubygems.org"];
569
- sha256 = "0ikjfwydgs08nm3xzc4cn4b6z6rmcrj2imp84xcnimy2wxa8w2xx";
570
- type = "gem";
571
- };
572
- version = "0.13.2";
573
- };
574
- simplecov_json_formatter = {
575
534
  groups = ["default"];
576
535
  platforms = [];
577
536
  source = {
578
537
  remotes = ["https://rubygems.org"];
579
- sha256 = "0a5l0733hj7sk51j81ykfmlk2vd5vaijlq9d5fn165yyx3xii52j";
538
+ sha256 = "118fdpg7h1ny1fz6kmiyz6gccvwmb23h6bhsi1hdpf7ib4byq8ia";
580
539
  type = "gem";
581
540
  };
582
- version = "0.1.4";
583
- };
584
- stringio = {
585
- groups = ["default" "development"];
586
- platforms = [];
587
- source = {
588
- remotes = ["https://rubygems.org"];
589
- sha256 = "1q92y9627yisykyscv0bdsrrgyaajc2qr56dwlzx7ysgigjv4z63";
590
- type = "gem";
591
- };
592
- version = "3.2.0";
541
+ version = "1.3.2";
593
542
  };
594
543
  sys-uname = {
595
544
  dependencies = ["ffi" "memoist3"];
@@ -597,20 +546,20 @@
597
546
  platforms = [];
598
547
  source = {
599
548
  remotes = ["https://rubygems.org"];
600
- sha256 = "05lsffr3v6brqyvhs621c8ghb211wac3l3a2nmgazs0fczn7h8pd";
549
+ sha256 = "0yvd71lzd2k46940k9l3l3yyjyxc4j1w6nmyrcjkqfdhj5j7wkbq";
601
550
  type = "gem";
602
551
  };
603
- version = "1.4.1";
552
+ version = "1.5.1";
604
553
  };
605
554
  thor = {
606
555
  groups = ["default" "development"];
607
556
  platforms = [];
608
557
  source = {
609
558
  remotes = ["https://rubygems.org"];
610
- sha256 = "0gcarlmpfbmqnjvwfz44gdjhcmm634di7plcx2zdgwdhrhifhqw7";
559
+ sha256 = "0wsy88vg2mazl039392hqrcwvs5nb9kq8jhhrrclir2px1gybag3";
611
560
  type = "gem";
612
561
  };
613
- version = "1.4.0";
562
+ version = "1.5.0";
614
563
  };
615
564
  tsort = {
616
565
  groups = ["default" "development"];
@@ -628,29 +577,29 @@
628
577
  platforms = [];
629
578
  source = {
630
579
  remotes = ["https://rubygems.org"];
631
- sha256 = "0hiwhnqpq271xqari6mg996fgjps42sffm9cpk6ljn8sd2srdp8c";
580
+ sha256 = "04xnl0zwpjjvxipd6rdnxkm11pfhbhhi3179yzv51nqi9dmacyjb";
632
581
  type = "gem";
633
582
  };
634
- version = "3.2.0";
583
+ version = "3.3.0";
635
584
  };
636
585
  unicode-emoji = {
637
586
  groups = ["default" "development"];
638
587
  platforms = [];
639
588
  source = {
640
589
  remotes = ["https://rubygems.org"];
641
- sha256 = "03zqn207zypycbz5m9mn7ym763wgpk7hcqbkpx02wrbm1wank7ji";
590
+ sha256 = "1kp89lja8ii7l6f0bq5vdxq1p3kxr3a2qmmhdc38qdwh6akjzh0i";
642
591
  type = "gem";
643
592
  };
644
- version = "4.2.0";
593
+ version = "4.3.0";
645
594
  };
646
595
  yard = {
647
596
  groups = ["development"];
648
597
  platforms = [];
649
598
  source = {
650
599
  remotes = ["https://rubygems.org"];
651
- sha256 = "03q1hf12csqy5q2inafzi44179zaq9n5yrb0k2j2llqhzcmbh7vj";
600
+ sha256 = "0lfwngmsz3xq9k9la9890cqpm4vk3rda4171yzms7f3w7x4i3qjj";
652
601
  type = "gem";
653
602
  };
654
- version = "0.9.38";
603
+ version = "0.9.45";
655
604
  };
656
605
  }
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "strscan" # for StringScanner
4
+
3
5
  module Bashcov
4
6
  # Detect shell scripts
5
7
  class Detective
data/lib/bashcov/lexer.rb CHANGED
@@ -15,6 +15,34 @@ module Bashcov
15
15
  # Lines containing only one of these keywords are irrelevant for coverage
16
16
  IGNORE_IS = %w[esac if then else elif fi while do done { } ;; ( )].freeze
17
17
 
18
+ # Constructs spanning multiple lines, as +[regexp, forward]+ pairs tried in
19
+ # order. Regexps are anchored with +\G+ to match from a given line offset.
20
+ MULTILINE_PATTERNS = [
21
+ # multi-line arrays
22
+ [/\G[^\n]*\b=\([^()]*\)/, false],
23
+
24
+ # heredoc, possibly with a quoted delimiter (e.g. 'EOF', "EOF" or \EOF) -
25
+ # ends at the first line holding only the delimiter, which `<<-` also
26
+ # allows to be indented with tabs
27
+ [/\G[^\n]+<<[ \t]*\\?['"]?(\w+)['"]?[^\n]*\n(?:[^\n]*\n)*?\1$/, true],
28
+ [/\G[^\n]+<<-[ \t]*\\?['"]?(\w+)['"]?[^\n]*\n(?:[^\n]*\n)*?\t*\1$/, true],
29
+
30
+ # multiline string concatenated with backslashes
31
+ [/\G[^\n]+\\$(\s*['"][^'"]*['"]\s*\\$){1,}\s*['"][^'"]*['"]\s*$/, true],
32
+
33
+ # multiline string concatenated with newlines, possibly opened after a
34
+ # line continuation (but never after an unescaped newline) - this must
35
+ # come before simple line continuations which would claim the opening
36
+ # line otherwise - unlike single quotes, double quotes may contain escaped
37
+ # characters such as \"
38
+ *[false, true].product([["'", /[^']*/], ['"', /(?:[^"\\]|\\.)*/m]]).map do |forward, (char, body)|
39
+ [/\G[^\n]+(?:[ \t=]|\\\n[ \t]*)+#{char}#{body}#{char}/m, forward]
40
+ end,
41
+
42
+ # simple line continuations with backslashes
43
+ [/\G([^\n&|;]*[^\\&|;](\\\\)*\\\n)+[^\n&|;]*[^\n\\&|;](\\\\)*$/, true],
44
+ ].freeze
45
+
18
46
  # @param [String] filename File to analyze
19
47
  # @param [Hash] coverage Coverage with executed lines marked
20
48
  # @raise [ArgumentError] if the given +filename+ is invalid.
@@ -28,55 +56,46 @@ module Bashcov
28
56
  # Process and complete initial coverage.
29
57
  # @return [void]
30
58
  def complete_coverage
31
- lines = File.read(@filename).encode("utf-8", invalid: :replace).lines
32
-
33
- lines.each_with_index do |line, lineno|
34
- # multi-line arrays
35
- mark_multiline(
36
- lines, lineno,
37
- /\A[^\n]*\b=\([^()]*\)/,
38
- forward: false
39
- )
40
-
41
- # heredoc
42
- mark_multiline(
43
- lines, lineno,
44
- /\A[^\n]+<<-?\s*'?(\w+)'?.*$.*\1/m
45
- )
46
-
47
- # multiline string concatenated with backslashes
48
- mark_multiline(
49
- lines, lineno,
50
- /\A[^\n]+\\$(\s*['"][^'"]*['"]\s*\\$){1,}\s*['"][^'"]*['"]\s*$/
51
- )
52
-
53
- # simple line continuations with backslashes
54
- mark_multiline(
55
- lines, lineno,
56
- /\A([^\n&|;]*[^\\&|;](\\\\)*\\\n)+[^\n&|;]*[^\n\\&|;](\\\\)*$/
57
- )
58
-
59
- # multiline string concatenated with newlines
60
- %w[' "].each do |char|
61
- mark_multiline(
62
- lines, lineno,
63
- /\A[^\n]+[\s=]+#{char}[^#{char}]*#{char}/m,
64
- forward: false
65
- )
66
- end
67
-
68
- mark_line(line, lineno)
59
+ content = File.read(@filename).encode("utf-8", invalid: :replace)
60
+ lines = content.lines
61
+ offsets = lines.each_with_object([0]) { |line, memo| memo << (memo.last + line.size) }
62
+
63
+ lineno = 0
64
+ while lineno < lines.size
65
+ # skip ahead past a multiline construct once its lines are marked, but
66
+ # recheck its last line as it may open another one, e.g. `a'; b='`
67
+ last = mark_multilines(content, offsets[lineno], lineno) || lineno
68
+ lineno.upto(last) { |sub_lineno| mark_line(lines[sub_lineno], sub_lineno) }
69
+ lineno = (last > lineno ? last : last + 1)
69
70
  end
70
71
  end
71
72
 
72
73
  private
73
74
 
74
- def mark_multiline(lines, lineno, regexp, forward: true)
75
- seek_forward = lines[lineno..].join
76
- return unless (multiline_match = seek_forward.match(regexp))
75
+ # @return [Integer, nil] last line of the multiline construct starting at
76
+ # +lineno+, if any
77
+ def mark_multilines(content, offset, lineno)
78
+ MULTILINE_PATTERNS.each do |regexp, forward|
79
+ last = mark_multiline(content, offset, lineno, regexp, forward: forward)
80
+ return last if last
81
+ end
82
+
83
+ nil
84
+ end
85
+
86
+ def mark_multiline(content, offset, lineno, regexp, forward: true)
87
+ # +regexp+ is anchored with \G so it only matches from +offset+
88
+ return unless (multiline_match = content.match(regexp, offset))
77
89
 
78
90
  length = multiline_match.to_s.count($/)
79
91
  first, last = lineno + 1, lineno + length
92
+
93
+ # skip if we are already inside marked multiline string - only inner
94
+ # lines are checked since Bash may report the hit on the last line
95
+ # (e.g. `readonly` before Bash 5.3), which is also the next line when
96
+ # the string spans only two lines
97
+ return unless first.upto(last - 1).all? { |i| @coverage[i].nil? }
98
+
80
99
  range = (forward ? first.upto(last) : (last - 1).downto(first - 1))
81
100
  reference_lineno = (forward ? first - 1 : last)
82
101
 
@@ -87,6 +106,8 @@ module Bashcov
87
106
  # mark related lines with the same coverage as the reference line
88
107
  @coverage[sub_lineno] ||= @coverage[reference_lineno]
89
108
  end
109
+
110
+ last if length.positive?
90
111
  end
91
112
 
92
113
  def mark_line(line, lineno)
@@ -178,7 +178,7 @@ module Bashcov
178
178
  end
179
179
 
180
180
  def convert_coverage
181
- @coverage.transform_keys(&:to_s)
181
+ @coverage.transform_keys(&:to_s).transform_values { |lines| { "lines" => lines } }
182
182
  end
183
183
  end
184
184
  end
@@ -3,5 +3,5 @@
3
3
  # :nodoc:
4
4
  module Bashcov
5
5
  # Current Bashcov version
6
- VERSION = "3.3.0"
6
+ VERSION = "4.0.1"
7
7
  end
@@ -85,7 +85,7 @@ module Bashcov
85
85
 
86
86
  field_count = FIELDS.length
87
87
  fields = @field_stream.each(
88
- self.class.delimiter, field_count, PS4_START_REGEXP
88
+ self.class.delimiter, field_count, PS4_START_REGEXP,
89
89
  )
90
90
 
91
91
  # +take(field_count)+ would be more natural here, but doesn't seem to
@@ -124,7 +124,7 @@ module Bashcov
124
124
  return
125
125
  else
126
126
  raise XtraceError.new(
127
- "expected integer for LINENO, got #{lineno.inspect}", @files
127
+ "expected integer for LINENO, got #{lineno.inspect}", @files,
128
128
  )
129
129
  end
130
130
 
data/lib/bashcov.rb CHANGED
@@ -10,7 +10,7 @@ require "bashcov/version"
10
10
  module Bashcov
11
11
  # A +Struct+ to store Bashcov configuration
12
12
  Options = Struct.new(
13
- *%i[skip_uncovered mute bash_path root_directory command command_name]
13
+ *%i[skip_uncovered mute bash_path root_directory command command_name],
14
14
  )
15
15
 
16
16
  class << self
data/screenshot.png ADDED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bashcov
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.0
4
+ version: 4.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cédric Félizard
@@ -15,28 +15,28 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '0.21'
18
+ version: '1.1'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '0.21'
25
+ version: '1.1'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: aruba
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
- - - ">="
30
+ - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '0'
32
+ version: 2.4.1
33
33
  type: :development
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
- - - ">="
37
+ - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '0'
39
+ version: 2.4.1
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: benchmark
42
42
  requirement: !ruby/object:Gem::Requirement
@@ -69,16 +69,16 @@ dependencies:
69
69
  name: cucumber
70
70
  requirement: !ruby/object:Gem::Requirement
71
71
  requirements:
72
- - - ">="
72
+ - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: '0'
74
+ version: 11.1.1
75
75
  type: :development
76
76
  prerelease: false
77
77
  version_requirements: !ruby/object:Gem::Requirement
78
78
  requirements:
79
- - - ">="
79
+ - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: '0'
81
+ version: 11.1.1
82
82
  - !ruby/object:Gem::Dependency
83
83
  name: ffi
84
84
  requirement: !ruby/object:Gem::Requirement
@@ -244,8 +244,8 @@ files:
244
244
  - lib/bashcov/runner.rb
245
245
  - lib/bashcov/version.rb
246
246
  - lib/bashcov/xtrace.rb
247
+ - screenshot.png
247
248
  - shell.nix
248
- - test.sh
249
249
  homepage: https://github.com/infertux/bashcov
250
250
  licenses:
251
251
  - MIT
@@ -268,7 +268,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
268
268
  - !ruby/object:Gem::Version
269
269
  version: '0'
270
270
  requirements: []
271
- rubygems_version: 4.0.6
271
+ rubygems_version: 4.0.22
272
272
  specification_version: 4
273
273
  summary: Code coverage tool for Bash
274
274
  test_files: []
data/test.sh DELETED
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env bash
2
-
3
- set -euo pipefail
4
-
5
- jobs=$(grep -o '^[a-z].*:$' .gitlab-ci.yml | tr -d ':' | grep -Ev '^(before_script)$')
6
-
7
- for job in $jobs; do
8
- echo "Running ${job}..."
9
- gitlab-runner exec docker "$job"
10
- done