summaryrefslogtreecommitdiff
path: root/spec/syntax_suggest/unit/explain_syntax_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/syntax_suggest/unit/explain_syntax_spec.rb')
-rw-r--r--spec/syntax_suggest/unit/explain_syntax_spec.rb255
1 files changed, 255 insertions, 0 deletions
diff --git a/spec/syntax_suggest/unit/explain_syntax_spec.rb b/spec/syntax_suggest/unit/explain_syntax_spec.rb
new file mode 100644
index 0000000000..c62a42b925
--- /dev/null
+++ b/spec/syntax_suggest/unit/explain_syntax_spec.rb
@@ -0,0 +1,255 @@
+# frozen_string_literal: true
+
+require_relative "../spec_helper"
+
+module SyntaxSuggest
+ RSpec.describe "ExplainSyntax" do
+ it "handles shorthand syntaxes with non-bracket characters" do
+ source = <<~EOM
+ %Q* lol
+ EOM
+
+ explain = ExplainSyntax.new(
+ code_lines: CodeLine.from_source(source)
+ ).call
+
+ expect(explain.missing).to eq([])
+ expect(explain.errors.join.strip).to_not be_empty
+ end
+
+ it "handles %w[]" do
+ source = <<~EOM
+ node.is_a?(Op) && %w[| ||].include?(node.value) &&
+ EOM
+
+ explain = ExplainSyntax.new(
+ code_lines: CodeLine.from_source(source)
+ ).call
+
+ expect(explain.missing).to eq([])
+ end
+
+ it "doesn't falsely identify strings or symbols as critical chars" do
+ source = <<~EOM
+ a = ['(', '{', '[', '|']
+ EOM
+
+ explain = ExplainSyntax.new(
+ code_lines: CodeLine.from_source(source)
+ ).call
+
+ expect(explain.missing).to eq([])
+
+ source = <<~EOM
+ a = [:'(', :'{', :'[', :'|']
+ EOM
+
+ explain = ExplainSyntax.new(
+ code_lines: CodeLine.from_source(source)
+ ).call
+
+ expect(explain.missing).to eq([])
+ end
+
+ it "finds missing |" do
+ source = <<~EOM
+ Foo.call do |
+ end
+ EOM
+
+ explain = ExplainSyntax.new(
+ code_lines: CodeLine.from_source(source)
+ ).call
+
+ expect(explain.missing).to eq(["|"])
+ expect(explain.errors).to eq([explain.why("|")])
+ end
+
+ it "finds missing {" do
+ source = <<~EOM
+ class Cat
+ lol = {
+ end
+ EOM
+
+ explain = ExplainSyntax.new(
+ code_lines: CodeLine.from_source(source)
+ ).call
+
+ expect(explain.missing).to eq(["}"])
+ expect(explain.errors).to eq([explain.why("}")])
+ end
+
+ it "finds missing }" do
+ source = <<~EOM
+ def foo
+ lol = "foo" => :bar }
+ end
+ EOM
+
+ explain = ExplainSyntax.new(
+ code_lines: CodeLine.from_source(source)
+ ).call
+
+ expect(explain.missing).to eq(["{"])
+ expect(explain.errors).to eq([explain.why("{")])
+ end
+
+ it "finds missing [" do
+ source = <<~EOM
+ class Cat
+ lol = [
+ end
+ EOM
+
+ explain = ExplainSyntax.new(
+ code_lines: CodeLine.from_source(source)
+ ).call
+
+ expect(explain.missing).to eq(["]"])
+ expect(explain.errors).to eq([explain.why("]")])
+ end
+
+ it "finds missing ]" do
+ source = <<~EOM
+ def foo
+ lol = ]
+ end
+ EOM
+
+ explain = ExplainSyntax.new(
+ code_lines: CodeLine.from_source(source)
+ ).call
+
+ expect(explain.missing).to eq(["["])
+ expect(explain.errors).to eq([explain.why("[")])
+ end
+
+ it "finds missing (" do
+ source = "def initialize; ); end"
+
+ explain = ExplainSyntax.new(
+ code_lines: CodeLine.from_source(source)
+ ).call
+
+ expect(explain.missing).to eq(["("])
+ expect(explain.errors).to eq([explain.why("(")])
+ end
+
+ it "finds missing )" do
+ source = "def initialize; (; end"
+
+ explain = ExplainSyntax.new(
+ code_lines: CodeLine.from_source(source)
+ ).call
+
+ expect(explain.missing).to eq([")"])
+ expect(explain.errors).to eq([explain.why(")")])
+ end
+
+ it "finds missing keyword" do
+ source = <<~EOM
+ class Cat
+ end
+ end
+ EOM
+
+ explain = ExplainSyntax.new(
+ code_lines: CodeLine.from_source(source)
+ ).call
+
+ expect(explain.missing).to eq(["keyword"])
+ expect(explain.errors).to eq([explain.why("keyword")])
+ end
+
+ it "finds missing end" do
+ source = <<~EOM
+ class Cat
+ def meow
+ end
+ EOM
+
+ explain = ExplainSyntax.new(
+ code_lines: CodeLine.from_source(source)
+ ).call
+
+ expect(explain.missing).to eq(["end"])
+ expect(explain.errors).to eq([explain.why("end")])
+ end
+
+ it "falls back to ripper on unknown errors" do
+ source = <<~EOM
+ class Cat
+ def meow
+ 1 *
+ end
+ end
+ EOM
+
+ explain = ExplainSyntax.new(
+ code_lines: CodeLine.from_source(source)
+ ).call
+
+ expect(explain.missing).to eq([])
+ expect(explain.errors).to eq(GetParseErrors.errors(source))
+ end
+
+ it "handles an unexpected rescue" do
+ source = <<~EOM
+ def foo
+ if bar
+ "baz"
+ else
+ "foo"
+ rescue FooBar
+ nil
+ end
+ EOM
+
+ explain = ExplainSyntax.new(
+ code_lines: CodeLine.from_source(source)
+ ).call
+
+ expect(explain.missing).to eq(["end"])
+ end
+
+ # String embeds are `"#{foo} <-- here`
+ #
+ # We need to count a `#{` as a `{`
+ # otherwise it will report that we are
+ # missing a curly when we are using valid
+ # string embed syntax
+ it "is not confused by valid string embed" do
+ source = <<~'EOM'
+ foo = "#{hello}"
+ EOM
+
+ explain = ExplainSyntax.new(
+ code_lines: CodeLine.from_source(source)
+ ).call
+ expect(explain.missing).to eq([])
+ end
+
+ # Missing string embed beginnings are not a
+ # syntax error. i.e. `"foo}"` or `"{foo}` or "#foo}"
+ # would just be strings with extra characters.
+ #
+ # However missing the end curly will trigger
+ # an error: i.e. `"#{foo`
+ #
+ # String embed beginning is a `#{` rather than
+ # a `{`, make sure we handle that case and
+ # report the correct missing `}` diagnosis
+ it "finds missing string embed end" do
+ source = <<~'EOM'
+ "#{foo
+ EOM
+
+ explain = ExplainSyntax.new(
+ code_lines: CodeLine.from_source(source)
+ ).call
+
+ expect(explain.missing).to eq(["}"])
+ end
+ end
+end