Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 9295b2f1394b
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 30a5cbb3f04a
Choose a head ref
  • 4 commits
  • 65 files changed
  • 1 contributor

Commits on Jun 29, 2015

  1. Squashed 'spec/mspec/' changes from 237524a..aefd6ad

    aefd6ad No need to register before anymore.
    4ffc230 Do not touch GC in the leakchecker
    70f1939 Adjust specs of the fixture helper
    4073e7a Use appropriate names in the fixture helper
    3af36bd Make the fixture helper return real paths
    d22e29a Import the LeakChecker from MRI test-all.
    1559f0f Remove unused state variable in argf helper
    
    git-subtree-dir: spec/mspec
    git-subtree-split: aefd6ad204fae34ff28913c0fa6ee899db36b329
    eregon committed Jun 29, 2015
    Copy the full SHA
    c552459 View commit details
  2. Copy the full SHA
    df4487c View commit details
  3. Squashed 'spec/ruby/' changes from d128ccf..0957d24

    0957d24 add BigDecimal#round special value specs
    dc36858 Fix spec title
    e145d75 Fix ARGF.seek spec
    a27e082 Add spec for Comparable#== without #<=>.
    7bbd215 Add a couple specs for constant resolution under module_eval
    0afb501 Add spec for resolving constants in Module#module_eval
    002731e Fix assertion in Module#module_eval.
    e450b4a Add spec for redo in a method
    63603b5 Add spec for next in a method
    09db199 Add spec for spawn redirect to [file,mode].
    071a996 Merge pull request #90 from ruby/time
    fdf1ced Fix typos
    f23b1cb Separate Time#<=> specs for millisecond vs microsecond precision
    b0a3bd4 Remove duplicated assertion
    541d1f7 Add spec for ARGF.argv
    a0a5ca8 Mention it "needs to be reviewed for spec completeness"
    4d680ed Remove extra backslash
    c6558a5 Merge pull request #88 from JuanitoFatas/feature/string-concat-by-spaces
    0258119 Update spec description for string literals
    bca9b5f Add two specs for string concatenations by spaces
    e9e02f5 Deduplicate example names
    4355c35 Merge pull request #87 from JuanitoFatas/string/unicode-normalize
    8626efe Fix unicode normalized spec
    f1de617 Remove unused IO in File#read spec
    293f6e4 Fix variable name in FIle#open
    62a7b2c Prefer setting autoclose to close + rescue
    d46d063 mkspec -c String; Copy spec content to mkspec generated spec
    50fade7 Apply code review changes
    7b6ce1f Try to clarify specs using the map_fd fixture.
    7747042 General cleanup of IO specs
    850f3ed Reorganize IO#popen specs
    b8dd40b Make sure the old IO is closed in IO#initialize spec
    136b80e Remove 1.8 readlines specs
    21b694d No need to check for closed? since IO#read examples never close themselves
    39d00ff Just use autoclose=false in socket for_fd specs
    f58eb48 No need to re-assign @fd in IO.sysopen spec
    b5aeacb Fix typo in CONTRIBUTING.md
    93bc817 Improve notes about mkspec
    43685be [core/string] Add String#unicode_normalize specs
    bb3e13d SVG Travis badge to please the eyes 👀
    ea9f106 Reorganize specs for multiple unnamed arguments.
    c95400b Merge pull request #83 from JuanitoFatas/proc/arguments
    5c9b2f1 [Language/block_spec] Add specs to check SyntaxError for block arguments
    113e7e6 Merge pull request #85 from ruby/use-standard-require
    24d31d1 Standardize require line for unboundmethod/shared/to_s.rb
    6f18131 update MSpec
    4527d8d The fixture helper now resolves real paths automatically
    5aa9134 Fix duplication with CODE_LOADING_DIR
    21dae98 Do not use the fixture helper on already expanded path
    4c4523c Just check for realpath in spec_helper.rb
    4dea397 Resolve realpath to fixture directory in -C spec
    a03ed0e Have a better check for CODE_LOADING_DIR and realpath
    a8884b9 Update required MSpec version
    c1ab544 Update instructions to directly use a MSpec checkout
    186300a Remove $SAFE-related specs.
    b762526 Merge pull request #82 from ruby/fix-ruby-version
    bc11d67 fixed wrong version of ruby
    2b8e36b Merge pull request #81 from ruby/remove-safe3
    7c640e2 discarded =3 example with Ruby 2.3
    19af98c Improve a bit Array#bsearch_index spec
    4e1a9b3 Merge pull request #78 from JuanitoFatas/feature/bsearch_index_spec
    c5374cd Merge pull request #79 from JuanitoFatas/feature/bundled-with
    18dd536 Clearer description of @array.bsearch_index { |x| (1 - x / 4) * (2**100)
    ea9bd82 Remove specs of break
    de6124c Add BUNDLED WITH to Gemfile.lock
    7732e00 Fix example descriptions and reorganize specs
    ac55574 Fix ARGF spec for Windows
    2cab1f3 Fix syntax errors
    0cf2e94 Port Array#bsearch_index spec from ruby/ruby@c64d283
    
    git-subtree-dir: spec/ruby
    git-subtree-split: 0957d245b6170480c880a62da19a335113cc8c84
    eregon committed Jun 29, 2015
    Copy the full SHA
    c9014f9 View commit details
  4. Copy the full SHA
    30a5cbb View commit details
Showing with 783 additions and 408 deletions.
  1. +0 −1 spec/mspec/lib/mspec/helpers/argf.rb
  2. +13 −8 spec/mspec/lib/mspec/helpers/fixture.rb
  3. +292 −0 spec/mspec/lib/mspec/runner/actions/leakchecker.rb
  4. +2 −0 spec/mspec/lib/mspec/runner/formatters/dotted.rb
  5. +8 −7 spec/mspec/spec/helpers/fixture_spec.rb
  6. +24 −6 spec/ruby/CONTRIBUTING.md
  7. +5 −2 spec/ruby/Gemfile.lock
  8. +15 −21 spec/ruby/README.md
  9. +0 −2 spec/ruby/command_line/dash_upper_c_spec.rb
  10. +1 −2 spec/ruby/core/argf/argf_spec.rb
  11. +19 −0 spec/ruby/core/argf/argv_spec.rb
  12. +1 −3 spec/ruby/core/argf/binmode_spec.rb
  13. +87 −0 spec/ruby/core/array/bsearch_index_spec.rb
  14. +5 −11 spec/ruby/core/file/new_spec.rb
  15. +7 −14 spec/ruby/core/file/open_spec.rb
  16. +3 −9 spec/ruby/core/io/dup_spec.rb
  17. +2 −2 spec/ruby/core/io/each_byte_spec.rb
  18. +1 −1 spec/ruby/core/io/each_codepoint_spec.rb
  19. +18 −13 spec/ruby/core/io/eof_spec.rb
  20. +1 −1 spec/ruby/core/io/external_encoding_spec.rb
  21. +2 −2 spec/ruby/core/io/getbyte_spec.rb
  22. +2 −2 spec/ruby/core/io/getc_spec.rb
  23. +8 −8 spec/ruby/core/io/gets_spec.rb
  24. +6 −5 spec/ruby/core/io/initialize_spec.rb
  25. +10 −14 spec/ruby/core/io/inspect_spec.rb
  26. +3 −3 spec/ruby/core/io/internal_encoding_spec.rb
  27. +2 −2 spec/ruby/core/io/lineno_spec.rb
  28. +1 −1 spec/ruby/core/io/lines_spec.rb
  29. +2 −2 spec/ruby/core/io/pid_spec.rb
  30. +17 −21 spec/ruby/core/io/pipe_spec.rb
  31. +30 −11 spec/ruby/core/io/popen_spec.rb
  32. +1 −1 spec/ruby/core/io/printf_spec.rb
  33. +2 −2 spec/ruby/core/io/puts_spec.rb
  34. +2 −2 spec/ruby/core/io/read_nonblock_spec.rb
  35. +4 −7 spec/ruby/core/io/read_spec.rb
  36. +1 −1 spec/ruby/core/io/shared/chars.rb
  37. +2 −2 spec/ruby/core/io/shared/each.rb
  38. +2 −1 spec/ruby/core/io/shared/new.rb
  39. +2 −2 spec/ruby/core/io/shared/pos.rb
  40. +0 −33 spec/ruby/core/io/shared/readlines.rb
  41. +2 −2 spec/ruby/core/io/shared/tty.rb
  42. +2 −2 spec/ruby/core/io/shared/write.rb
  43. +0 −1 spec/ruby/core/io/sysopen_spec.rb
  44. +100 −0 spec/ruby/core/string/unicode_normalized_spec.rb
  45. +0 −6 spec/ruby/core/thread/safe_level_spec.rb
  46. +16 −1 spec/ruby/core/time/comparison_spec.rb
  47. +2 −2 spec/ruby/core/unboundmethod/shared/to_s.rb
  48. +14 −0 spec/ruby/language/block_spec.rb
  49. +1 −5 spec/ruby/language/shared/__FILE__.rb
  50. +19 −0 spec/ruby/language/string_spec.rb
  51. +0 −28 spec/ruby/library/delegate/delegator/trust_spec.rb
  52. +0 −9 spec/ruby/library/erb/new_spec.rb
  53. +0 −16 spec/ruby/library/erb/result_spec.rb
  54. +3 −20 spec/ruby/library/socket/basicsocket/for_fd_spec.rb
  55. +2 −14 spec/ruby/library/socket/unixserver/for_fd_spec.rb
  56. +0 −4 spec/ruby/optional/capi/ext/rubyspec.h
  57. +0 −37 spec/ruby/optional/capi/ext/safe_spec.c
  58. +0 −19 spec/ruby/optional/capi/safe_spec.rb
  59. +1 −1 spec/ruby/shared/io/putc.rb
  60. +1 −1 spec/ruby/shared/process/abort.rb
  61. +7 −6 spec/ruby/shared/process/exec.rb
  62. +5 −3 spec/ruby/shared/process/fixtures/map_fd.rb
  63. +2 −2 spec/ruby/shared/process/spawn.rb
  64. +1 −1 spec/ruby/shared/time/strftime_for_time.rb
  65. +2 −3 spec/ruby/spec_helper.rb
1 change: 0 additions & 1 deletion spec/mspec/lib/mspec/helpers/argf.rb
Original file line number Diff line number Diff line change
@@ -31,7 +31,6 @@ def argf(argv)
file2.close if !file2.closed? and file2 != STDIN
@argf = nil
@__mspec_saved_argf_file__ = nil
@__mspec_saved_argf_caller__ = nil
end
end
end
21 changes: 13 additions & 8 deletions spec/mspec/lib/mspec/helpers/fixture.rb
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
class Object
# Returns the name of a fixture file by adjoining the directory
# of the +dir+ argument with "fixtures" and the contents of the
# of the +file+ argument with "fixtures" and the contents of the
# +args+ array. For example,
#
# +dir+ == "some/path"
# +file+ == "some/example_spec.rb"
#
# and
#
# +args+ == ["dir", "file.txt"]
# +args+ == ["subdir", "file.txt"]
#
# then the result is the expanded path of
#
# "some/fixtures/dir/file.txt".
def fixture(dir, *args)
path = File.dirname(dir)
# "some/fixtures/subdir/file.txt".
def fixture(file, *args)
path = File.dirname(file)
path = path[0..-7] if path[-7..-1] == "/shared"
dir = path[-9..-1] == "/fixtures" ? "" : "fixtures"
File.expand_path(File.join(path, dir, args))
fixtures = path[-9..-1] == "/fixtures" ? "" : "fixtures"
if File.respond_to?(:realpath)
path = File.realpath(path)
else
path = File.expand_path(path)
end
File.join(path, fixtures, args)
end
end
292 changes: 292 additions & 0 deletions spec/mspec/lib/mspec/runner/actions/leakchecker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
# Adapted from ruby's test/lib/leakchecker.rb.
# Ruby's 2-clause BSDL follows.

# Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.

# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.

# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.

class LeakChecker
def initialize
@fd_info = find_fds
@tempfile_info = find_tempfiles
@thread_info = find_threads
@env_info = find_env
@argv_info = find_argv
@encoding_info = find_encodings
end

def check(test_name)
@no_leaks = true
leaks = [
check_fd_leak(test_name),
check_thread_leak(test_name),
check_tempfile_leak(test_name),
check_env(test_name),
check_argv(test_name),
check_encodings(test_name)
]
GC.start if leaks.any?
return leaks.none?
end

private
def find_fds
fd_dir = "/proc/self/fd"
if File.directory?(fd_dir)
fds = Dir.open(fd_dir) {|d|
a = d.grep(/\A\d+\z/, &:to_i)
if d.respond_to? :fileno
a -= [d.fileno]
end
a
}
fds.sort
else
[]
end
end

def check_fd_leak(test_name)
leaked = false
live1 = @fd_info
if IO.respond_to?(:console) and (m = IO.method(:console)).arity.nonzero?
m[:close]
end
live2 = find_fds
fd_closed = live1 - live2
if !fd_closed.empty?
fd_closed.each {|fd|
puts "Closed file descriptor: #{test_name}: #{fd}"
}
end
fd_leaked = live2 - live1
if !fd_leaked.empty?
leaked = true
h = {}
ObjectSpace.each_object(IO) {|io|
inspect = io.inspect
begin
autoclose = io.autoclose?
fd = io.fileno
rescue IOError # closed IO object
next
end
(h[fd] ||= []) << [io, autoclose, inspect]
}
fd_leaked.each {|fd|
str = ''
if h[fd]
str << ' :'
h[fd].map {|io, autoclose, inspect|
s = ' ' + inspect
s << "(not-autoclose)" if !autoclose
s
}.sort.each {|s|
str << s
}
end
puts "Leaked file descriptor: #{test_name}: #{fd}#{str}"
}
#system("lsof -p #$$") if !fd_leaked.empty?
h.each {|fd, list|
next if list.length <= 1
if 1 < list.count {|io, autoclose, inspect| autoclose }
str = list.map {|io, autoclose, inspect| " #{inspect}" + (autoclose ? "(autoclose)" : "") }.sort.join
puts "Multiple autoclose IO object for a file descriptor:#{str}"
end
}
end
@fd_info = live2
return leaked
end

def extend_tempfile_counter
return if defined? LeakChecker::TempfileCounter
m = Module.new {
@count = 0
class << self
attr_accessor :count
end

def new(data)
LeakChecker::TempfileCounter.count += 1
super(data)
end
}
LeakChecker.const_set(:TempfileCounter, m)

class << Tempfile::Remover
prepend LeakChecker::TempfileCounter
end
end

def find_tempfiles(prev_count=-1)
return [prev_count, []] unless defined? Tempfile
extend_tempfile_counter
count = TempfileCounter.count
if prev_count == count
[prev_count, []]
else
tempfiles = ObjectSpace.each_object(Tempfile).find_all {|t| t.path }
[count, tempfiles]
end
end

def check_tempfile_leak(test_name)
return false unless defined? Tempfile
count1, initial_tempfiles = @tempfile_info
count2, current_tempfiles = find_tempfiles(count1)
leaked = false
tempfiles_leaked = current_tempfiles - initial_tempfiles
if !tempfiles_leaked.empty?
leaked = true
list = tempfiles_leaked.map {|t| t.inspect }.sort
list.each {|str|
puts "Leaked tempfile: #{test_name}: #{str}"
}
tempfiles_leaked.each {|t| t.close! }
end
@tempfile_info = [count2, initial_tempfiles]
return leaked
end

def find_threads
Thread.list.find_all {|t|
t != Thread.current && t.alive?
}
end

def check_thread_leak(test_name)
live1 = @thread_info
live2 = find_threads
thread_finished = live1 - live2
leaked = false
if !thread_finished.empty?
list = thread_finished.map {|t| t.inspect }.sort
list.each {|str|
puts "Finished thread: #{test_name}: #{str}"
}
end
thread_leaked = live2 - live1
if !thread_leaked.empty?
leaked = true
list = thread_leaked.map {|t| t.inspect }.sort
list.each {|str|
puts "Leaked thread: #{test_name}: #{str}"
}
end
@thread_info = live2
return leaked
end

def find_env
ENV.to_h
end

def check_env(test_name)
old_env = @env_info
new_env = find_env
return false if old_env == new_env
(old_env.keys | new_env.keys).sort.each {|k|
if old_env.has_key?(k)
if new_env.has_key?(k)
if old_env[k] != new_env[k]
puts "Environment variable changed: #{test_name} : #{k.inspect} changed : #{old_env[k].inspect} -> #{new_env[k].inspect}"
end
else
puts "Environment variable changed: #{test_name} : #{k.inspect} deleted"
end
else
if new_env.has_key?(k)
puts "Environment variable changed: #{test_name} : #{k.inspect} added"
else
flunk "unreachable"
end
end
}
@env_info = new_env
return true
end

def find_argv
ARGV.map { |e| e.dup }
end

def check_argv(test_name)
old_argv = @argv_info
new_argv = find_argv
leaked = false
if new_argv != old_argv
puts "ARGV changed: #{test_name} : #{old_argv.inspect} to #{new_argv.inspect}"
@argv_info = new_argv
leaked = true
end
return leaked
end

def find_encodings
[Encoding.default_internal, Encoding.default_external]
end

def check_encodings(test_name)
old_internal, old_external = @encoding_info
new_internal, new_external = find_encodings
leaked = false
if new_internal != old_internal
leaked = true
puts "Encoding.default_internal changed: #{test_name} : #{old_internal} to #{new_internal}"
end
if new_external != old_external
leaked = true
puts "Encoding.default_external changed: #{test_name} : #{old_external} to #{new_external}"
end
@encoding_info = [new_internal, new_external]
return leaked
end

def puts(*args)
if @no_leaks
@no_leaks = false
print "\n"
end
super(*args)
end
end

class LeakCheckerAction
def register
MSpec.register :start, self
MSpec.register :after, self
end

def start
@checker = LeakChecker.new
end

def after(state)
unless @checker.check(state.description)
if state.example
puts state.example.source_location.join(':')
end
end
end
end
2 changes: 2 additions & 0 deletions spec/mspec/lib/mspec/runner/formatters/dotted.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
require 'mspec/expectations/expectations'
require 'mspec/runner/actions/timer'
require 'mspec/runner/actions/tally'
require 'mspec/runner/actions/leakchecker' if ENV['CHECK_LEAKS']

class DottedFormatter
attr_reader :exceptions, :timer, :tally
@@ -24,6 +25,7 @@ def initialize(out=nil)
def register
(@timer = TimerAction.new).register
(@tally = TallyAction.new).register
LeakCheckerAction.new.register if ENV['CHECK_LEAKS']
@counter = @tally.counter

MSpec.register :exception, self
15 changes: 8 additions & 7 deletions spec/mspec/spec/helpers/fixture_spec.rb
Original file line number Diff line number Diff line change
@@ -4,21 +4,22 @@

describe Object, "#fixture" do
before :each do
@dir = File.expand_path(Dir.pwd)
@dir = File.realpath("..", __FILE__)
end

it "returns the expanded path to a fixture file" do
name = fixture("some/path/file.rb", "dir", "file.txt")
name.should == "#{@dir}/some/path/fixtures/dir/file.txt"
name = fixture(__FILE__, "subdir", "file.txt")
name.should == "#{@dir}/fixtures/subdir/file.txt"
end

it "omits '/shared' if it is the suffix of the directory string" do
name = fixture("some/path/shared/file.rb", "dir", "file.txt")
name.should == "#{@dir}/some/path/fixtures/dir/file.txt"
name = fixture("#{@dir}/shared/file.rb", "subdir", "file.txt")
name.should == "#{@dir}/fixtures/subdir/file.txt"
end

it "does not append '/fixtures' if it is the suffix of the directory string" do
name = fixture("some/path/fixtures/file.rb", "dir", "file.txt")
name.should == "#{@dir}/some/path/fixtures/dir/file.txt"
commands_dir = "#{File.dirname(@dir)}/commands"
name = fixture("#{commands_dir}/fixtures/file.rb", "subdir", "file.txt")
name.should == "#{commands_dir}/fixtures/subdir/file.txt"
end
end
Loading