diff options
Diffstat (limited to 'test/prism/api')
| -rw-r--r-- | test/prism/api/command_line_test.rb | 114 | ||||
| -rw-r--r-- | test/prism/api/dump_test.rb | 56 | ||||
| -rw-r--r-- | test/prism/api/freeze_test.rb | 65 | ||||
| -rw-r--r-- | test/prism/api/lex_test.rb | 23 | ||||
| -rw-r--r-- | test/prism/api/parse_comments_test.rb | 33 | ||||
| -rw-r--r-- | test/prism/api/parse_stream_test.rb | 118 | ||||
| -rw-r--r-- | test/prism/api/parse_success_test.rb | 16 | ||||
| -rw-r--r-- | test/prism/api/parse_test.rb | 189 |
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 |
