summaryrefslogtreecommitdiff
path: root/test/prism/api
diff options
context:
space:
mode:
Diffstat (limited to 'test/prism/api')
-rw-r--r--test/prism/api/command_line_test.rb114
-rw-r--r--test/prism/api/dump_test.rb56
-rw-r--r--test/prism/api/freeze_test.rb65
-rw-r--r--test/prism/api/lex_test.rb23
-rw-r--r--test/prism/api/parse_comments_test.rb33
-rw-r--r--test/prism/api/parse_stream_test.rb118
-rw-r--r--test/prism/api/parse_success_test.rb16
-rw-r--r--test/prism/api/parse_test.rb189
8 files changed, 614 insertions, 0 deletions
diff --git a/test/prism/api/command_line_test.rb b/test/prism/api/command_line_test.rb
new file mode 100644
index 0000000000..e53d18703a
--- /dev/null
+++ b/test/prism/api/command_line_test.rb
@@ -0,0 +1,114 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class CommandLineTest < TestCase
+ def test_command_line_p
+ program = Prism.parse("1", command_line: "p").value
+ statements = program.statements.body
+
+ assert_equal 2, statements.length
+ assert_kind_of CallNode, statements.last
+ assert_equal :print, statements.last.name
+ end
+
+ def test_command_line_n
+ program = Prism.parse("1", command_line: "n").value
+ statements = program.statements.body
+
+ assert_equal 1, statements.length
+ assert_kind_of WhileNode, statements.first
+
+ predicate = statements.first.predicate
+ assert_kind_of CallNode, predicate
+ assert_equal :gets, predicate.name
+
+ arguments = predicate.arguments.arguments
+ assert_equal 1, arguments.length
+ assert_equal :$/, arguments.first.name
+ end
+
+ def test_command_line_a
+ program = Prism.parse("1", command_line: "na").value
+ statements = program.statements.body
+
+ assert_equal 1, statements.length
+ assert_kind_of WhileNode, statements.first
+
+ statement = statements.first.statements.body.first
+ assert_kind_of GlobalVariableWriteNode, statement
+ assert_equal :$F, statement.name
+ end
+
+ def test_command_line_l
+ program = Prism.parse("1", command_line: "nl").value
+ statements = program.statements.body
+
+ assert_equal 1, statements.length
+ assert_kind_of WhileNode, statements.first
+
+ predicate = statements.first.predicate
+ assert_kind_of CallNode, predicate
+ assert_equal :gets, predicate.name
+
+ arguments = predicate.arguments
+ assert arguments.contains_keywords?
+
+ arguments = predicate.arguments.arguments
+ assert_equal 2, arguments.length
+ assert_equal :$/, arguments.first.name
+ assert_equal "chomp", arguments.last.elements.first.key.unescaped
+ end
+
+ def test_command_line_e
+ result = Prism.parse("1 if 2..3")
+ assert_equal 2, result.warnings.length
+
+ result = Prism.parse("1 if 2..3", command_line: "e")
+ assert_equal 0, result.warnings.length
+ end
+
+ def test_command_line_x_implicit
+ result = Prism.parse_statement(<<~RUBY, main_script: true)
+ #!/bin/bash
+ exit 1
+
+ #!/usr/bin/env ruby
+ 1
+ RUBY
+
+ assert_kind_of IntegerNode, result
+ end
+
+ def test_command_line_x_explicit
+ result = Prism.parse_statement(<<~RUBY, command_line: "x")
+ exit 1
+
+ #!/usr/bin/env ruby
+ 1
+ RUBY
+
+ assert_kind_of IntegerNode, result
+ end
+
+ def test_command_line_x_implicit_fail
+ result = Prism.parse(<<~RUBY, main_script: true)
+ #!/bin/bash
+ exit 1
+ RUBY
+
+ assert_equal 1, result.errors.length
+ assert_equal :load, result.errors.first.level
+ end
+
+ def test_command_line_x_explicit_fail
+ result = Prism.parse(<<~RUBY, command_line: "x")
+ exit 1
+ RUBY
+
+ assert_equal 1, result.errors.length
+ assert_equal :load, result.errors.first.level
+ end
+ end
+end
diff --git a/test/prism/api/dump_test.rb b/test/prism/api/dump_test.rb
new file mode 100644
index 0000000000..941088e159
--- /dev/null
+++ b/test/prism/api/dump_test.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+return if ENV["PRISM_BUILD_MINIMAL"]
+
+require_relative "../test_helper"
+
+module Prism
+ class DumpTest < TestCase
+ Fixture.each do |fixture|
+ define_method(fixture.test_name) { assert_dump(fixture) }
+ end
+
+ def test_dump
+ filepath = __FILE__
+ source = File.read(filepath, binmode: true, external_encoding: Encoding::UTF_8)
+
+ assert_equal Prism.lex(source, filepath: filepath).value, Prism.lex_file(filepath).value
+ assert_equal Prism.dump(source, filepath: filepath), Prism.dump_file(filepath)
+
+ serialized = Prism.dump(source, filepath: filepath)
+ ast1 = Prism.load(source, serialized).value
+ ast2 = Prism.parse(source, filepath: filepath).value
+ ast3 = Prism.parse_file(filepath).value
+
+ assert_equal_nodes ast1, ast2
+ assert_equal_nodes ast2, ast3
+ end
+
+ def test_dump_file
+ assert_nothing_raised do
+ Prism.dump_file(__FILE__)
+ end
+
+ error = assert_raise Errno::ENOENT do
+ Prism.dump_file("idontexist.rb")
+ end
+
+ assert_equal "No such file or directory - idontexist.rb", error.message
+
+ assert_raise TypeError do
+ Prism.dump_file(nil)
+ end
+ end
+
+ private
+
+ def assert_dump(fixture)
+ source = fixture.read
+
+ result = Prism.parse(source, filepath: fixture.path)
+ dumped = Prism.dump(source, filepath: fixture.path)
+
+ assert_equal_nodes(result.value, Prism.load(source, dumped).value)
+ end
+ end
+end
diff --git a/test/prism/api/freeze_test.rb b/test/prism/api/freeze_test.rb
new file mode 100644
index 0000000000..bf91792e69
--- /dev/null
+++ b/test/prism/api/freeze_test.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class FreezeTest < TestCase
+ def test_parse
+ assert_frozen(Prism.parse("1 + 2; %i{foo} + %i{bar}", freeze: true))
+ end
+
+ def test_offsets_usable
+ node = Prism.parse_statement("1 + 2", freeze: true)
+ assert_equal(1, node.start_line)
+ end
+
+ def test_lex
+ assert_frozen(Prism.lex("1 + 2; %i{foo} + %i{bar}", freeze: true))
+ end
+
+ def test_parse_lex
+ assert_frozen(Prism.parse_lex("1 + 2; %i{foo} + %i{bar}", freeze: true))
+ assert_frozen(Prism.parse_lex("# encoding: euc-jp\n%i{foo}", freeze: true))
+ end
+
+ def test_parse_comments
+ assert_frozen(Prism.parse_comments("# comment", freeze: true))
+ end
+
+ def test_parse_stream
+ assert_frozen(Prism.parse_stream(StringIO.new("1 + 2; %i{foo} + %i{bar}"), freeze: true))
+ end
+
+ if !ENV["PRISM_BUILD_MINIMAL"]
+ def test_dump
+ assert_frozen(Prism.dump("1 + 2; %i{foo} + %i{bar}", freeze: true))
+ end
+ end
+
+ private
+
+ def assert_frozen_each(value)
+ assert_predicate value, :frozen?
+
+ value.instance_variables.each do |name|
+ case (child = value.instance_variable_get(name))
+ when Array
+ child.each { |item| assert_frozen_each(item) }
+ when Hash
+ child.each { |key, item| assert_frozen_each(key); assert_frozen_each(item) }
+ else
+ assert_frozen_each(child)
+ end
+ end
+ end
+
+ if defined?(Ractor.shareable?)
+ def assert_frozen(value)
+ assert_frozen_each(value)
+ assert Ractor.shareable?(value), -> { binding.irb }
+ end
+ else
+ alias assert_frozen assert_frozen_each
+ end
+ end
+end
diff --git a/test/prism/api/lex_test.rb b/test/prism/api/lex_test.rb
new file mode 100644
index 0000000000..0b675b215f
--- /dev/null
+++ b/test/prism/api/lex_test.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class LexTest < TestCase
+ def test_lex_result
+ result = Prism.lex("")
+ assert_kind_of LexResult, result
+
+ result = Prism.lex_file(__FILE__)
+ assert_kind_of LexResult, result
+ end
+
+ def test_parse_lex_result
+ result = Prism.parse_lex("")
+ assert_kind_of ParseLexResult, result
+
+ result = Prism.parse_lex_file(__FILE__)
+ assert_kind_of ParseLexResult, result
+ end
+ end
+end
diff --git a/test/prism/api/parse_comments_test.rb b/test/prism/api/parse_comments_test.rb
new file mode 100644
index 0000000000..4dbcca1827
--- /dev/null
+++ b/test/prism/api/parse_comments_test.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class ParseCommentsTest < TestCase
+ def test_parse_comments
+ comments = Prism.parse_comments("# foo")
+
+ assert_kind_of Array, comments
+ assert_equal 1, comments.length
+ end
+
+ def test_parse_file_comments
+ comments = Prism.parse_file_comments(__FILE__)
+
+ assert_kind_of Array, comments
+ assert_equal 1, comments.length
+ end
+
+ def test_parse_file_comments_error
+ error = assert_raise Errno::ENOENT do
+ Prism.parse_file_comments("idontexist.rb")
+ end
+
+ assert_equal "No such file or directory - idontexist.rb", error.message
+
+ assert_raise TypeError do
+ Prism.parse_file_comments(nil)
+ end
+ end
+ end
+end
diff --git a/test/prism/api/parse_stream_test.rb b/test/prism/api/parse_stream_test.rb
new file mode 100644
index 0000000000..3bc86fbd61
--- /dev/null
+++ b/test/prism/api/parse_stream_test.rb
@@ -0,0 +1,118 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class ParseStreamTest < TestCase
+ def test_single_line
+ io = StringIO.new("1 + 2")
+ result = Prism.parse_stream(io)
+
+ assert result.success?
+ assert_kind_of Prism::CallNode, result.statement
+ end
+
+ def test_multi_line
+ io = StringIO.new("1 + 2\n3 + 4")
+ result = Prism.parse_stream(io)
+
+ assert result.success?
+ assert_kind_of Prism::CallNode, result.statement
+ assert_kind_of Prism::CallNode, result.statement
+ end
+
+ def test_multi_read
+ io = StringIO.new("a" * 4096 * 4)
+ result = Prism.parse_stream(io)
+
+ assert result.success?
+ assert_kind_of Prism::CallNode, result.statement
+ end
+
+ def test___END__
+ io = StringIO.new(<<~RUBY)
+ 1 + 2
+ 3 + 4
+ __END__
+ 5 + 6
+ RUBY
+ result = Prism.parse_stream(io)
+
+ assert result.success?
+ assert_equal 2, result.value.statements.body.length
+ assert_equal "5 + 6\n", io.read
+ end
+
+ def test_false___END___in_string
+ io = StringIO.new(<<~RUBY)
+ 1 + 2
+ 3 + 4
+ "
+ __END__
+ "
+ 5 + 6
+ RUBY
+ result = Prism.parse_stream(io)
+
+ assert result.success?
+ assert_equal 4, result.value.statements.body.length
+ end
+
+ def test_false___END___in_regexp
+ io = StringIO.new(<<~RUBY)
+ 1 + 2
+ 3 + 4
+ /
+ __END__
+ /
+ 5 + 6
+ RUBY
+ result = Prism.parse_stream(io)
+
+ assert result.success?
+ assert_equal 4, result.value.statements.body.length
+ end
+
+ def test_false___END___in_list
+ io = StringIO.new(<<~RUBY)
+ 1 + 2
+ 3 + 4
+ %w[
+ __END__
+ ]
+ 5 + 6
+ RUBY
+ result = Prism.parse_stream(io)
+
+ assert result.success?
+ assert_equal 4, result.value.statements.body.length
+ end
+
+ def test_false___END___in_heredoc
+ io = StringIO.new(<<~RUBY)
+ 1 + 2
+ 3 + 4
+ <<-EOF
+ __END__
+ EOF
+ 5 + 6
+ RUBY
+ result = Prism.parse_stream(io)
+
+ assert result.success?
+ assert_equal 4, result.value.statements.body.length
+ end
+
+ def test_nul_bytes
+ io = StringIO.new(<<~RUBY)
+ 1 # \0\0\0\t
+ 2 # \0\0\0
+ 3
+ RUBY
+ result = Prism.parse_stream(io)
+
+ assert result.success?
+ assert_equal 3, result.value.statements.body.length
+ end
+ end
+end
diff --git a/test/prism/api/parse_success_test.rb b/test/prism/api/parse_success_test.rb
new file mode 100644
index 0000000000..2caaa5136e
--- /dev/null
+++ b/test/prism/api/parse_success_test.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class ParseSuccessTest < TestCase
+ def test_parse_success?
+ assert Prism.parse_success?("1")
+ refute Prism.parse_success?("<>")
+ end
+
+ def test_parse_file_success?
+ assert Prism.parse_file_success?(__FILE__)
+ end
+ end
+end
diff --git a/test/prism/api/parse_test.rb b/test/prism/api/parse_test.rb
new file mode 100644
index 0000000000..c9a47c1a61
--- /dev/null
+++ b/test/prism/api/parse_test.rb
@@ -0,0 +1,189 @@
+# frozen_string_literal: true
+
+require_relative "../test_helper"
+
+module Prism
+ class ParseTest < TestCase
+ def test_parse_result
+ result = Prism.parse("")
+ assert_kind_of ParseResult, result
+
+ result = Prism.parse_file(__FILE__)
+ assert_kind_of ParseResult, result
+ end
+
+ def test_parse_empty_string
+ result = Prism.parse("")
+ assert_equal [], result.value.statements.body
+ end
+
+ def test_parse_takes_file_path
+ filepath = "filepath.rb"
+ result = Prism.parse("def foo; __FILE__; end", filepath: filepath)
+
+ assert_equal filepath, find_source_file_node(result.value).filepath
+ end
+
+ def test_parse_takes_line
+ line = 4
+ result = Prism.parse("def foo\n __FILE__\nend", line: line)
+
+ assert_equal line, result.value.location.start_line
+ assert_equal line + 1, find_source_file_node(result.value).location.start_line
+
+ result = Prism.parse_lex("def foo\n __FILE__\nend", line: line)
+ assert_equal line, result.value.first.location.start_line
+ end
+
+ def test_parse_takes_negative_lines
+ line = -2
+ result = Prism.parse("def foo\n __FILE__\nend", line: line)
+
+ assert_equal line, result.value.location.start_line
+ assert_equal line + 1, find_source_file_node(result.value).location.start_line
+
+ result = Prism.parse_lex("def foo\n __FILE__\nend", line: line)
+ assert_equal line, result.value.first.location.start_line
+ end
+
+ def test_parse_file
+ node = Prism.parse_file(__FILE__).value
+ assert_kind_of ProgramNode, node
+
+ error = assert_raise Errno::ENOENT do
+ Prism.parse_file("idontexist.rb")
+ end
+
+ assert_equal "No such file or directory - idontexist.rb", error.message
+
+ assert_raise TypeError do
+ Prism.parse_file(nil)
+ end
+ end
+
+ def test_parse_tempfile
+ Tempfile.create(["test_parse_tempfile", ".rb"]) do |t|
+ t.puts ["begin\n", " end\n"]
+ t.flush
+ Prism.parse_file(t.path)
+ end
+ end
+
+ if RUBY_ENGINE != "truffleruby"
+ def test_parse_nonascii
+ Dir.mktmpdir do |dir|
+ path = File.join(dir, "\u{3042 3044 3046 3048 304a}.rb".encode(Encoding::Windows_31J))
+ File.write(path, "ok")
+ Prism.parse_file(path)
+ end
+ end
+ end
+
+ def test_parse_directory
+ error = nil
+
+ begin
+ Prism.parse_file(__dir__)
+ rescue SystemCallError => error
+ end
+
+ assert_kind_of Errno::EISDIR, error
+ end
+
+ def test_partial_script
+ assert Prism.parse_failure?("break")
+ assert Prism.parse_success?("break", partial_script: true)
+
+ assert Prism.parse_failure?("next")
+ assert Prism.parse_success?("next", partial_script: true)
+
+ assert Prism.parse_failure?("redo")
+ assert Prism.parse_success?("redo", partial_script: true)
+
+ assert Prism.parse_failure?("yield")
+ assert Prism.parse_success?("yield", partial_script: true)
+ end
+
+ def test_version
+ assert Prism.parse_success?("1 + 1", version: "3.3")
+ assert Prism.parse_success?("1 + 1", version: "3.3.0")
+ assert Prism.parse_success?("1 + 1", version: "3.3.1")
+ assert Prism.parse_success?("1 + 1", version: "3.3.9")
+ assert Prism.parse_success?("1 + 1", version: "3.3.10")
+
+ assert Prism.parse_success?("1 + 1", version: "3.4")
+ assert Prism.parse_success?("1 + 1", version: "3.4.0")
+ assert Prism.parse_success?("1 + 1", version: "3.4.9")
+ assert Prism.parse_success?("1 + 1", version: "3.4.10")
+
+ assert Prism.parse_success?("1 + 1", version: "3.5")
+ assert Prism.parse_success?("1 + 1", version: "3.5.0")
+
+ assert Prism.parse_success?("1 + 1", version: "4.0")
+ assert Prism.parse_success?("1 + 1", version: "4.0.0")
+
+ assert Prism.parse_success?("1 + 1", version: "4.1")
+ assert Prism.parse_success?("1 + 1", version: "4.1.0")
+
+ assert Prism.parse_success?("1 + 1", version: "latest")
+
+ # Test edge case
+ error = assert_raise(ArgumentError) { Prism.parse("1 + 1", version: "latest2") }
+ assert_equal "invalid version: latest2", error.message
+
+ assert_raise ArgumentError do
+ Prism.parse("1 + 1", version: "3.3.a")
+ end
+
+ # Not supported version (too old)
+ assert_raise ArgumentError do
+ Prism.parse("1 + 1", version: "3.2.0")
+ end
+
+ # Not supported version (too new)
+ assert_raise ArgumentError do
+ Prism.parse("1 + 1", version: "3.6.0")
+ end
+ end
+
+ def test_version_current
+ if RUBY_VERSION >= "3.3"
+ assert Prism.parse_success?("1 + 1", version: "current")
+ else
+ assert_raise(CurrentVersionError) { Prism.parse_success?("1 + 1", version: "current") }
+ end
+ end
+
+ def test_nearest
+ assert Prism.parse_success?("1 + 1", version: "nearest")
+ end
+
+ def test_scopes
+ assert_kind_of Prism::CallNode, Prism.parse_statement("foo")
+ assert_kind_of Prism::LocalVariableReadNode, Prism.parse_statement("foo", scopes: [[:foo]])
+ assert_kind_of Prism::LocalVariableReadNode, Prism.parse_statement("foo", scopes: [Prism.scope(locals: [:foo])])
+
+ assert Prism.parse_failure?("foo(*)")
+ assert Prism.parse_success?("foo(*)", scopes: [Prism.scope(forwarding: [:*])])
+
+ assert Prism.parse_failure?("foo(**)")
+ assert Prism.parse_success?("foo(**)", scopes: [Prism.scope(forwarding: [:**])])
+
+ assert Prism.parse_failure?("foo(&)")
+ assert Prism.parse_success?("foo(&)", scopes: [Prism.scope(forwarding: [:&])])
+
+ assert Prism.parse_failure?("foo(...)")
+ assert Prism.parse_success?("foo(...)", scopes: [Prism.scope(forwarding: [:"..."])])
+ end
+
+ private
+
+ def find_source_file_node(program)
+ queue = [program]
+ while (node = queue.shift)
+ return node if node.is_a?(SourceFileNode)
+ queue.concat(node.compact_child_nodes)
+ end
+ end
+ end
+end