Skip to content

Commit

Permalink
BasicSocket#recv should mark the thread as sleeping
Browse files Browse the repository at this point in the history
Adds support for ir.exe -Ifoo;bar. Previously, we were not breaking it up into two paths.
The stricter tests in upper_dash_i_spec.rb caught two other issues:
- We should not replace \ with /.
- Output of spawned processes should be filtered to convert \r\n to \n
Fixed assert in OverloadResolver.cs
Adds tests for the tutorial sample to irtests.rb
  • Loading branch information
Shri Borde committed Aug 1, 2009
1 parent 4fb8e7c commit a3da993
Show file tree
Hide file tree
Showing 17 changed files with 115 additions and 43 deletions.

This file was deleted.

Expand Up @@ -29,7 +29,6 @@ core\array\multiply_tags.txt:0:critical:Array#* raises a NoMethodError if an ele
core\array\union_tags.txt:0:critical:Array#| properly handles recursive arrays
core\array\uniq_tags.txt:0:critical:Array#uniq properly handles recursive arrays
core\array\uniq_tags.txt:0:critical:Array#uniq! properly handles recursive arrays
core\kernel\sleep_tags.txt:3:critical:Kernel#sleep pauses execution indefinitely if not given a duration
core\process\times_tags.txt:0:unstable:Process.times returns current cpu times
core\string\process\wait_tags.txt:0:critical:Process.wait
core\string\process\wait2_tags.txt:0:critical:Process.wait2
Expand All @@ -50,5 +49,3 @@ library\resolv\get_name_tags.txt:0:critical:Resolv#getname
library\resolv\get_names_tags.txt:0:critical:Resolv#getnames
library\scanf\io\block_scanf_tags.txt:0:critical:IO#block_scanf passes each match to the block as an array
library\scanf\io\scanf_tags.txt:0:critical:IO#scanf with block passes each match to the block as an array
library\socket\basicsocket\recv_tags.txt:0:critical:BasicSocket#recv receives a specified number of bytes of a message from another socket
library\socket\basicsocket\recv_tags.txt:0:critical:BasicSocket#recv accepts flags to specify unusual receiving behaviour

This file was deleted.

Expand Up @@ -2,12 +2,40 @@

describe "The -I command line option" do
it "adds the path to the load path ($:)" do
ruby_exe("fixtures/loadpath.rb", :options => '-I fixtures', :dir => File.dirname(__FILE__)).should include("fixtures")
ruby_exe("fixtures/loadpath.rb", :options => '-I fixtures', :dir => File.dirname(__FILE__)).should =~ /^fixtures$/
end

it "allows different formats" do
['-I fixtures', '-Ifixtures', '-I"fixtures"', '-I./fixtures', '-I.\fixtures'].each do |format|
ruby_exe("fixtures/loadpath.rb", :options => format, :dir => File.dirname(__FILE__)).should include("fixtures")
[['-I fixtures', 'fixtures'],
['-Ifixtures', 'fixtures'],
['-I"fixtures"', 'fixtures'],
['-I./fixtures', './fixtures'],
['-I.\fixtures', '.\fixtures']].each do |command_line, resulting_path|
ruby_exe("fixtures/loadpath.rb", :options => command_line, :dir => File.dirname(__FILE__)).should =~ /^#{Regexp.escape(resulting_path)}$/
end
end

it "allows quoted paths with spaces" do
ruby_exe("fixtures/loadpath.rb", :options => '-I"foo bar"', :dir => File.dirname(__FILE__)).should =~ /^foo bar$/
end

it "concatenates adjacent quoted strings" do
ruby_exe("fixtures/loadpath.rb", :options => '-Ifoo"bar"baz', :dir => File.dirname(__FILE__)).should =~ /^foobarbaz$/
end

it "allows multiple paths separated with ;" do
ruby_exe("fixtures/loadpath.rb", :options => '-Ifoo;bar', :dir => File.dirname(__FILE__)).should =~ /^bar$/
end

it "treats ; as a separator even within a quoted string" do
ruby_exe("fixtures/loadpath.rb", :options => '-I"foo ; bar"', :dir => File.dirname(__FILE__)).should =~ /^foo $/
end

it "concatenates adjacent quoted strings, but separates at ;" do
ruby_exe("fixtures/loadpath.rb", :options => '-Ifoo"bar;baz"', :dir => File.dirname(__FILE__)).should =~ /^foobar$/
end

it "allows non-existent paths" do
ruby_exe("fixtures/loadpath.rb", :options => '-Inon-existent', :dir => File.dirname(__FILE__)).should =~ /^non-existent$/
end
end
Expand Up @@ -203,7 +203,11 @@ public static class KernelOps {
[RubyMethod("`", RubyMethodAttributes.PublicSingleton, BuildConfig = "!SILVERLIGHT")]
public static MutableString/*!*/ ExecuteCommand(RubyContext/*!*/ context, object self, [DefaultProtocol, NotNull]MutableString/*!*/ command) {
Process p = ExecuteProcessCapturingStandardOutput(GetShell(context, command));
MutableString result = MutableString.Create(p.StandardOutput.ReadToEnd());
string output = p.StandardOutput.ReadToEnd();
if (Environment.NewLine != "\n") {
output = output.Replace(Environment.NewLine, "\n");
}
MutableString result = MutableString.Create(output);
context.ChildProcessExitStatus = new RubyProcess.Status(p);
return result;
}
Expand Down Expand Up @@ -911,14 +915,14 @@ public static class KernelOps {

[RubyMethod("sleep", RubyMethodAttributes.PrivateInstance)]
[RubyMethod("sleep", RubyMethodAttributes.PublicSingleton)]
public static double Sleep(object self, double seconds) {
public static int Sleep(object self, double seconds) {
if (seconds < 0) {
throw RubyExceptions.CreateArgumentError("time interval must be positive");
}

double ms = seconds * 1000;
Thread.Sleep(ms > Int32.MaxValue ? Timeout.Infinite : (int)ms);
return seconds;
return (int)seconds;
}

//split
Expand Down
Expand Up @@ -15,17 +15,13 @@

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using Microsoft.Scripting;
using System.Dynamic;
using Microsoft.Scripting.Actions;
using Microsoft.Scripting.Runtime;
using Microsoft.Scripting.Utils;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using IronRuby.Runtime;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using Microsoft.Scripting;
using Microsoft.Scripting.Runtime;

namespace IronRuby.Builtins {
/// <summary>
Expand Down Expand Up @@ -76,6 +72,7 @@ internal class RubyThreadInfo {
private readonly int _id;
private ThreadGroup _group;
private readonly Thread _thread;
private bool _blocked;
private bool _abortOnException;
private AutoResetEvent _runSignal = new AutoResetEvent(false);
private bool _isSleeping;
Expand Down Expand Up @@ -159,6 +156,16 @@ internal class RubyThreadInfo {
internal object Result { get; set; }
internal bool CreatedFromRuby { get; set; }
internal bool ExitRequested { get; set; }

internal bool Blocked {
get {
return _blocked;
}
set {
System.Diagnostics.Debug.Assert(Thread.CurrentThread == _thread);
_blocked = value;
}
}

internal bool AbortOnException {
get {
Expand Down Expand Up @@ -516,7 +523,11 @@ internal class RubyThreadInfo {
}

if ((state & ThreadState.Running) == ThreadState.Running) {
return RubyThreadStatus.Running;
if (info.Blocked) {
return RubyThreadStatus.Sleeping;
} else {
return RubyThreadStatus.Running;
}
}

throw new ArgumentException("unknown thread status: " + state);
Expand Down
Expand Up @@ -2931,7 +2931,7 @@ public sealed class BuiltinsLibraryInitializer : IronRuby.Builtins.LibraryInitia
module.DefineLibraryMethod("sleep", 0x52,
new System.Action<System.Object>(IronRuby.Builtins.KernelOps.Sleep),
new System.Func<System.Object, System.Int32, System.Int32>(IronRuby.Builtins.KernelOps.Sleep),
new System.Func<System.Object, System.Double, System.Double>(IronRuby.Builtins.KernelOps.Sleep)
new System.Func<System.Object, System.Double, System.Int32>(IronRuby.Builtins.KernelOps.Sleep)
);

module.DefineLibraryMethod("sprintf", 0x52,
Expand Down Expand Up @@ -3183,7 +3183,7 @@ public sealed class BuiltinsLibraryInitializer : IronRuby.Builtins.LibraryInitia
module.DefineLibraryMethod("sleep", 0x61,
new System.Action<System.Object>(IronRuby.Builtins.KernelOps.Sleep),
new System.Func<System.Object, System.Int32, System.Int32>(IronRuby.Builtins.KernelOps.Sleep),
new System.Func<System.Object, System.Double, System.Double>(IronRuby.Builtins.KernelOps.Sleep)
new System.Func<System.Object, System.Double, System.Int32>(IronRuby.Builtins.KernelOps.Sleep)
);

module.DefineLibraryMethod("sprintf", 0x61,
Expand Down
Expand Up @@ -56,7 +56,13 @@ public TCPServer(RubyContext/*!*/ context, Socket/*!*/ socket)
IAsyncResult result = Interlocked.Exchange(ref _acceptResult, null);

if (result == null) {
return Socket.Accept();
ThreadOps.RubyThreadInfo info = ThreadOps.RubyThreadInfo.FromThread(Thread.CurrentThread);
info.Blocked = true;
try {
return Socket.Accept();
} finally {
info.Blocked = false;
}
}

// wait until accept finishes:
Expand Down
19 changes: 16 additions & 3 deletions Merlin/Main/Languages/Ruby/Ruby/Hosting/RubyOptionsParser.cs
Expand Up @@ -71,6 +71,16 @@ private sealed class CustomTraceFilter : TraceFilter {
}
#endif

private static string[] GetPaths(string input) {
string[] paths = StringUtils.Split(input, new char[] { Path.PathSeparator }, Int32.MaxValue, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < paths.Length; i++) {
// Trim any occurrances of "
string[] parts = StringUtils.Split(paths[i], new char[] { '"' }, Int32.MaxValue, StringSplitOptions.RemoveEmptyEntries);
paths[i] = String.Concat(parts);
}
return paths;
}

/// <exception cref="Exception">On error.</exception>
protected override void ParseArgument(string arg) {
ContractUtils.RequiresNotNull(arg, "arg");
Expand Down Expand Up @@ -186,11 +196,14 @@ private sealed class CustomTraceFilter : TraceFilter {

default:
if (arg.StartsWith("-I")) {
string includePaths;
if (arg == "-I") {
_loadPaths.Add(PopNextArg());
includePaths = PopNextArg();
} else {
_loadPaths.Add(arg.Substring(2));
includePaths = arg.Substring(2);
}

_loadPaths.AddRange(GetPaths(includePaths));
break;
}

Expand Down Expand Up @@ -228,7 +241,7 @@ private sealed class CustomTraceFilter : TraceFilter {
try {
string rubylib = Environment.GetEnvironmentVariable("RUBYLIB");
if (rubylib != null) {
_loadPaths.AddRange(rubylib.Split(Path.PathSeparator));
_loadPaths.AddRange(GetPaths(rubylib));
}
} catch (SecurityException) {
// nop
Expand Down
2 changes: 1 addition & 1 deletion Merlin/Main/Languages/Ruby/Ruby/Runtime/Loader.cs
Expand Up @@ -146,7 +146,7 @@ private struct CompiledFile {

if (options.HasSearchPaths) {
foreach (string path in options.SearchPaths) {
loadPaths.Add(MutableString.Create(path.Replace('\\', '/')));
loadPaths.Add(MutableString.Create(path));
}
}

Expand Down
Expand Up @@ -29,6 +29,11 @@ def self.ensure_script_method
end

class RedirectingOutputStream < System::IO::Stream
def initialize
@encoding = System::Text::UTF8Encoding.new
super
end

def can_seek
false
end
Expand All @@ -43,11 +48,9 @@ def can_write

# TODO - This does not deal with any encoding issues
def write(buffer, offset, count)
char_array = System::Array[System::Char].new(buffer.length)
buffer.each_index { |idx| char_array[idx] = buffer[idx] }
# Do the actual write. Note that this will automatically honor $stdout redirection
# of the ScriptEngine of the tutorial application.
print System::String.clr_new(char_array, offset, count)
print @encoding.get_string(buffer, offset, count)
end
end
end
Expand All @@ -60,8 +63,8 @@ module Hosting
class ScriptEngine
def redirect_output
stream = HostingTutorial::RedirectingOutputStream.new
# TODO - This does not deal with any encoding issues
self.runtime.i_o.set_output(stream, System::Text::UTF8Encoding.new)
@encoding ||= System::Text::UTF8Encoding.new
self.runtime.io.set_output(stream, @encoding)
end
end
end
Expand Down
Expand Up @@ -605,7 +605,8 @@ def self.snoop_add_handler name, obj
:setup => lambda {
# TODO - Position the form so that it is not hidden behind the current window
},
:code => "f.text = 'Hello'"
:code => "f.text = 'Hello'",
:test_hook => lambda { |type, bind| bind.f.close if type == :cleanup }
) { |iar| /hello/i =~ iar.bind.f.text }
end

Expand Down Expand Up @@ -754,7 +755,8 @@ def on_click(f, a)
However, we will just clear out the content so that we can use the same window in the
next chapter.
},
:code => 'w.content = nil'
:code => 'w.content = nil',
:test_hook => lambda { |type, bind| bind.w.close if type == :cleanup }
) { |iar| not iar.bind.w.content }
end

Expand Down
Expand Up @@ -132,6 +132,7 @@ def self.run_test context, chapter
result = context.interact task.code_string
assert_task_success task, task.code_string, result
end
task.test_hook.call(:cleanup, context.bind) if task.test_hook
end
end
end
Expand Down
13 changes: 11 additions & 2 deletions Merlin/Main/Languages/Ruby/Samples/Tutorial/tutorial.rb
Expand Up @@ -44,14 +44,16 @@ class Task
attr :code
attr :title
attr :source_files # Files used by the task. The user might want to browse these files
attr :test_hook

def initialize title, description, run_unless, setup, code, source_files, &success_evaluator
def initialize title, description, run_unless, setup, code, source_files, test_hook, &success_evaluator
@title = title
@description = description
@run_unless = run_unless
@setup = setup
@code = code
@source_files = source_files
@test_hook = test_hook
@success_evaluator = success_evaluator
end

Expand Down Expand Up @@ -438,7 +440,14 @@ def chapter name
def task(options, &success_evaluator)
options = {}.merge(options)
Thread.current[:chapter].tasks << Tutorial::Task.new(
options[:title], options[:body], options[:run_unless], options[:setup], options[:code], options[:source_files], &success_evaluator)
options[:title],
options[:body],
options[:run_unless],
options[:setup],
options[:code],
options[:source_files],
options[:test_hook],
&success_evaluator)
end
end

Expand Down
3 changes: 2 additions & 1 deletion Merlin/Main/Languages/Ruby/Scripts/irtests.rb
Expand Up @@ -19,7 +19,8 @@ def initialize
:RubySpec_C => "#{mspec_base} :core2 :lib2",
:RubyGems => "#{ir} #{@root}\\Languages\\Ruby\\Tests\\Scripts\\RubyGemsTests.rb",
:Rake => "#{ir} #{@root}\\Languages\\Ruby\\Tests\\Scripts\\RakeTests.rb",
:Yaml => "#{ir} #{@root}\\..\\External.LCA_RESTRICTED\\Languages\\IronRuby\\yaml\\YamlTest\\yaml_test_suite.rb"
:Yaml => "#{ir} #{@root}\\..\\External.LCA_RESTRICTED\\Languages\\IronRuby\\yaml\\YamlTest\\yaml_test_suite.rb",
:Tutorial => "#{ir} #{@root}\\Languages\\Ruby\\Samples\\Tutorial\\test\\test_console.rb"
}
end

Expand Down
6 changes: 3 additions & 3 deletions Merlin/Main/Languages/Ruby/rake/test.rake
Expand Up @@ -70,13 +70,13 @@ namespace :test do
IRTest.test(:Yaml)
end

desc "(NOT IMPLEMENTED) Run tests corresponding to samples"
desc "Run tests corresponding to samples"
task :samples => :happy do

IRTest.test(:Tutorial)
end

desc "Run all tests"
task :all => [:compile, "compile:ironpython", :smoke, :legacy, :spec_a, :spec_b, :spec_c, :apps]
task :all => [:compile, "compile:ironpython", :smoke, :legacy, :spec_a, :spec_b, :spec_c, :apps, :samples]
end

task :default => "test:all"
Expand Up @@ -418,7 +418,7 @@ public abstract partial class OverloadResolver {
if (result.Count == 0) {
// attempt generic method type inference
foreach (ApplicableCandidate candidate in candidates) {
if (!candidate.Method.Method.ContainsGenericParameters) {
if (!candidate.Method.Method.IsGenericMethodDefinition) {
continue;
}

Expand Down

0 comments on commit a3da993

Please sign in to comment.