Skip to content

Commit

Permalink
Merge branch 'master' into truffle-head
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisseaton committed Nov 17, 2016
2 parents 621352d + c400403 commit 94171da
Show file tree
Hide file tree
Showing 85 changed files with 1,076 additions and 285 deletions.
83 changes: 41 additions & 42 deletions BUILDING.md
Expand Up @@ -101,66 +101,75 @@ mvn -pl core
mvn -pl truffle
```


### Day to Day Testing

For normal day-to-day testing, we recommend running the Ruby (MRI) tests
For normal day-to-day testing, we recommend running the Ruby specs. We have set aside a
"fast" grouping that takes only a couple minutes to run:

```
jruby -S rake spec:ruby:fast
```

For a more intensive workout, you can also run the Ruby (MRI) tests
via the following rake command:

```
bin/jruby -S rake test:mri
jruby -S rake test:mri
```

This suite takes a while to complete, so if you want to run an individual file
from MRI's tests (under test/mri), use one of the following commands:

# Run a specific test method in a specific file
```
jruby <test file> -n <specific test method>
```
#### Run a specific test from the MRI suite

# Run a test file with known-failing tests excluded
The MRI suite (under `test/mri`) has a runner script in `test/mri/runner.rb` that sets up
an appropriate test environment. Many of the MRI tests will need to be run via this script.
```
EXCLUDES=test/mri/excludes bin/jruby -r test/mri_test_env.rb test/mri/runner.rb -q -- <test file>
```
#### Run a single spec
```
bin/jruby spec/mspec/bin/mspec run spec/ruby/core/symbol/length_spec.rb
jruby test/mri/runner.rb test/mri/<path to test>
```

#### Run a single spec with remote debugging
```
bin/jruby spec/mspec/bin/mspec run -T-J-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 spec/ruby/core/symbol/length_spec.rb
```
You can pass `-v` to the runner for verbose output or `-n test_method_name` to only run a single test method.

#### Run a test file with known-failing tests excluded

The runner script provides a mechanism for "excluding" known failing tests. Ruby scripts under `test/mri/exclude`, named based on the name of the test case's class, exclude with comment tests known to fail.

To run a given test with these excludes enabled, you can use the EXCLUDES environment variable:

Additional tests may be run through mspec.
```
bin/jruby -S mspec -B spec/jruby.2.2.mspec -t bin/jruby -G fails ci <test files>
EXCLUDES=test/mri/excludes bin/jruby test/mri/runner.rb <test file>
```

For more complete assurance, you can also run 1.9 RubySpecs via the
following command:
#### Run a single Ruby spec

Individual specs can be run with the mspec tool:

```
jruby spec/mspec/bin/mspec ci
jruby spec/mspec/bin/mspec ci spec/ruby/<path to spec>
```

And if you are making changes that would affect JRuby's core runtime
or embedding APIs, you should run JRuby's Java-based unit tests via
If `ci` is omitted or replaced with `run` you will see any specs known to fail. The `ci` command
avoids running those specs.

#### Run JRuby with with remote debugging

If you are familiar with Java debuggers, you can attach one to a JRuby process using the JDWP agent.
The exact flag may vary with debugger and platform:

```
mvn -Ptest
bin/jruby -T-J-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 <rest of arguments>
```
#### JRuby internal unit tests

On travis the following tests will run
If you are making changes that would affect JRuby's core runtime
or embedding APIs, you should run JRuby's Java-based unit tests via

```
mvn -Ptest
mvn -Prake -Dtask=test:extended
mvn -Prake -Dtask=spec:ci\_interpreted\_travis
mvn -Ptruffle
```

#### Tests for other ways of deploying and packaging JRuby

There are some maven integration tests (i.e. consistency test if all gems are included, osgi test, etc) for the various distributions of JRuby which can be invoked with

```
Expand All @@ -169,21 +178,11 @@ mvn -Pcomplete -Dinvoker.skip=false
mvn -Pdist -Dinvoker.skip=false
```

### Just Like CI

Our [CI](https://travis-ci.org/jruby/jruby) runs the following three commands (in essence):

```
rake test:extended
jruby spec/mspec/bin/mspec ci
jruby --1.8 spec/mspec/bin/mspec ci
```
#### Just Like CI

The complete CI test suite will take anywhere from 20 to 45 minutes to
complete, but provides the most accurate indication of the stability of
your local JRuby source.
JRuby runs CI tests on TravisCI. See [.travis.yml](https://github.com/jruby/jruby/blob/master/.travis.yml).

### maven integration tests - -Pjruby-complete or -Pmain
#### maven integration tests - -Pjruby-complete or -Pmain

maven integration test will use the packed maven artifact to run the tests in a forked maven instance. these maven projects are locatated in

Expand Down
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -33,14 +33,14 @@ To run JRuby you will need a JRE (the JVM runtime environment) version 7 or high
Your operating system may provide a JRE and JRuby in a package manager, but you may find that this
version is very old.

An alternative is to use one of the Ruby version managers.
An alternative is to use one of the [Ruby version managers](https://www.ruby-lang.org/en/documentation/installation/#managers).

For [`rbenv`](https://github.com/sstephenson/rbenv) you will need the
[`ruby-build`](https://github.com/sstephenson/ruby-build) plugin. You may find that your system
package manager can provide these. Then you can run:

```
$ rbenv install jruby-9.1.2.0
$ rbenv install jruby-9.1.6.0
```

For [`rvm`](https://rvm.io) you can simply do:
Expand Down
5 changes: 5 additions & 0 deletions core/src/main/java/org/jruby/RubyIO.java
Expand Up @@ -2805,6 +2805,11 @@ static IRubyObject nonblockEOF(final Ruby runtime, final boolean noException) {

@JRubyMethod(name = "readpartial", required = 1, optional = 1)
public IRubyObject readpartial(ThreadContext context, IRubyObject[] args) {
// ruby bug 11885
if (args.length == 2) {
args[1] = args[1].convertToString();
}

IRubyObject value = getPartial(context, args, false, false);

if (value.isNil()) {
Expand Down
4 changes: 3 additions & 1 deletion core/src/main/java/org/jruby/RubyKernel.java
Expand Up @@ -815,6 +815,7 @@ public static IRubyObject sprintf(ThreadContext context, IRubyObject recv, IRuby
public static IRubyObject raise(ThreadContext context, IRubyObject recv, IRubyObject[] args, Block block) {
final Ruby runtime = context.runtime;
int argc = args.length;
boolean forceCause = false;

// semi extract_raise_opts :
IRubyObject cause = null;
Expand All @@ -824,6 +825,7 @@ public static IRubyObject raise(ThreadContext context, IRubyObject recv, IRubyOb
RubyHash opt = (RubyHash) last; RubySymbol key;
if ( ! opt.isEmpty() && ( opt.has_key_p( key = runtime.newSymbol("cause") ) == runtime.getTrue() ) ) {
cause = opt.delete(context, key, Block.NULL_BLOCK);
forceCause = true;
if ( opt.isEmpty() && --argc == 0 ) { // more opts will be passed along
throw runtime.newArgumentError("only cause is given with no arguments");
}
Expand Down Expand Up @@ -868,7 +870,7 @@ public static IRubyObject raise(ThreadContext context, IRubyObject recv, IRubyOb
printExceptionSummary(context, runtime, raise.getException());
}

if (argc > 0 && raise.getException().getCause() == UNDEF && cause != raise.getException()) {
if (forceCause || argc > 0 && raise.getException().getCause() == UNDEF && cause != raise.getException()) {
raise.getException().setCause(cause);
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/RubyMath.java
Expand Up @@ -758,7 +758,7 @@ public NemesLogGamma(double x) {
}

double int_part = (int) x;
sign = (int_part % 2 == 0 && (x - int_part) != 0.0 && (x < 0)) ? -1 : 1;
sign = ((x == -0.0) || (int_part % 2 == 0 && (x - int_part) != 0.0 && (x < 0))) ? -1 : 1;
if ((x - int_part) == 0.0 && 0 < int_part && int_part <= FACTORIAL.length) {
value = Math.log(FACTORIAL[(int) int_part - 1]);
}
Expand Down
Expand Up @@ -78,7 +78,39 @@ public static MethodHandle generate(final int size) {
final String clsPath = "org/jruby/runtime/scopes/DynamicScope" + size;
final String clsName = clsPath.replaceAll("/", ".");

// try to load the class, in case we have parallel generation happening
Class p;

try {
p = CDCL.loadClass(clsName);
} catch (ClassNotFoundException cnfe) {
// try again under lock
synchronized (CDCL) {
try {
p = CDCL.loadClass(clsName);
} catch (ClassNotFoundException cnfe2) {
// proceed to actually generate the class
p = generateInternal(size, clsPath, clsName);
}
}
}

// acquire constructor handle and store it
try {
MethodHandle mh = MethodHandles.lookup().findConstructor(p, MethodType.methodType(void.class, StaticScope.class, DynamicScope.class));
mh = mh.asType(MethodType.methodType(DynamicScope.class, StaticScope.class, DynamicScope.class));
MethodHandle previousMH = specializedFactories.putIfAbsent(size, mh);
if (previousMH != null) mh = previousMH;

return mh;
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private static Class generateInternal(final int size, final String clsPath, final String clsName) {
// ensure only one thread will attempt to generate and define the new class
synchronized (CDCL) {
// create a new one
final String[] newFields = varList(size);

Expand Down Expand Up @@ -255,16 +287,7 @@ public static MethodHandle generate(final int size) {
}});
}};

Class p = defineClass(jiteClass);

MethodHandle mh = MethodHandles.lookup().findConstructor(p, MethodType.methodType(void.class, StaticScope.class, DynamicScope.class));
mh = mh.asType(MethodType.methodType(DynamicScope.class, StaticScope.class, DynamicScope.class));
MethodHandle previousMH = specializedFactories.putIfAbsent(size, mh);
if (previousMH != null) mh = previousMH;

return mh;
} catch (Exception e) {
throw new RuntimeException(e);
return defineClass(jiteClass);
}
}

Expand Down Expand Up @@ -310,7 +333,15 @@ private static MethodHandle getClassFromSize(int size) {
}

private static Class defineClass(JiteClass jiteClass) {
return CDCL.defineClass(jiteClass.getClassName().replaceAll("/", "."), jiteClass.toBytes(JDKVersion.V1_7));
return CDCL.defineClass(classNameFromJiteClass(jiteClass), jiteClass.toBytes(JDKVersion.V1_7));
}

private static Class loadClass(JiteClass jiteClass) throws ClassNotFoundException {
return CDCL.loadClass(classNameFromJiteClass(jiteClass));
}

private static String classNameFromJiteClass(JiteClass jiteClass) {
return jiteClass.getClassName().replaceAll("/", ".");
}

private static String[] varList(int size) {
Expand Down
32 changes: 30 additions & 2 deletions core/src/test/java/org/jruby/runtime/TestDynamicScope.java
@@ -1,15 +1,43 @@
package org.jruby.runtime;

import java.lang.invoke.MethodHandle;
import java.util.ArrayList;
import junit.framework.TestCase;
import org.jruby.RubyBasicObject;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.scope.DynamicScopeGenerator;
import org.junit.Assert;
import org.junit.Test;

import java.util.Arrays;

public class TestDynamicScope extends TestCase {
@Test
public void testMultithreadedScopeGeneration() throws Throwable {
final ArrayList<MethodHandle> result = new ArrayList<>();
final int numberOfThreads = 10;

Thread[] threads = new Thread[numberOfThreads];
for(int i = 0; i < numberOfThreads; i++) {
threads[i] = new Thread(new Runnable(){
public void run() {
MethodHandle dynamicScope = DynamicScopeGenerator.generate(10);
synchronized(result) {
result.add(dynamicScope);
}
}
});
threads[i].start();
}

for(int i = 0; i < numberOfThreads; i++) {
threads[i].join();
}

Assert.assertEquals(numberOfThreads, result.size());
for (int i = 0; i < result.size() - 1; ++i) {
Assert.assertEquals(result.get(i), result.get(i+1));
}
}

@Test
public void testScopeGeneration() throws Throwable {
for (int i = 0; i < 100; i++) {
Expand Down
1 change: 1 addition & 0 deletions spec/tags/ruby/core/math/lgamma_tags.txt
@@ -0,0 +1 @@
fails:Math.lgamma returns [Infinity, 1] when passed 0
1 change: 1 addition & 0 deletions spec/truffle/tags/core/math/lgamma_tags.txt
@@ -0,0 +1 @@
fails:Math.lgamma returns [Infinity, 1] when passed 0
13 changes: 10 additions & 3 deletions test/mri/-ext-/float/test_nextafter.rb
Expand Up @@ -46,9 +46,16 @@ class TestFloatExt < Test::Unit::TestCase
if v1 == 0
s1 = 1.0/v1 < 0 ? "negative-zero" : "positive-zero"
s2 = 1.0/v2 < 0 ? "negative-zero" : "positive-zero"
assert_equal(s1, s2,
"Bug::Float.missing_nextafter(#{'%a' % n1}, #{'%a' % n2}) = #{'%a' % v1} != " +
"#{'%a' % v2} = Bug::Float.system_nextafter(#{'%a' % n1}, #{'%a' % n2})")
begin
assert_equal(s1, s2,
"Bug::Float.missing_nextafter(#{'%a' % n1}, #{'%a' % n2}) = #{'%a' % v1} != " +
"#{'%a' % v2} = Bug::Float.system_nextafter(#{'%a' % n1}, #{'%a' % n2})")
rescue Minitest::Assertion
if /aix/ =~ RUBY_PLATFORM
skip "Known bug in nextafter(3) on AIX"
end
raise $!
end
end
end
}
Expand Down
6 changes: 6 additions & 0 deletions test/mri/-ext-/string/test_cstr.rb
Expand Up @@ -36,6 +36,12 @@ def test_frozen
end
end

def test_rb_str_new_frozen_embed
str = Bug::String.cstr_noembed("rbconfig.rb")
str = Bug::String.rb_str_new_frozen(str)
assert_equal true, Bug::String.cstr_embedded?(str)
end

WCHARS = [Encoding::UTF_16BE, Encoding::UTF_16LE, Encoding::UTF_32BE, Encoding::UTF_32LE]

def test_wchar_embed
Expand Down
22 changes: 22 additions & 0 deletions test/mri/-ext-/struct/test_duplicate.rb
@@ -0,0 +1,22 @@
# frozen_string_literal: false
require 'test/unit'
require "-test-/struct"

class Bug::Struct::Test_Duplicate < Test::Unit::TestCase
def test_new_dupilicate
bug12291 = '[ruby-core:74971] [Bug #12291]'
assert_raise_with_message(ArgumentError, /duplicate member/, bug12291) {
Bug::Struct.new_duplicate(nil, "a")
}
assert_raise_with_message(ArgumentError, /duplicate member/, bug12291) {
Bug::Struct.new_duplicate("X", "a")
}
end

def test_new_dupilicate_under
bug12291 = '[ruby-core:74971] [Bug #12291]'
assert_raise_with_message(ArgumentError, /duplicate member/, bug12291) {
Bug::Struct.new_duplicate_under("x", "a")
}
end
end
8 changes: 8 additions & 0 deletions test/mri/-ext-/symbol/test_inadvertent_creation.rb
Expand Up @@ -54,6 +54,14 @@ def test_module_const_get
assert_not_interned_error(cl, :const_get, name.to_sym)
end

def test_module_const_get_toplevel
bug12089 = '[ruby-dev:49498] [Bug #12089]'
name = noninterned_name("A")
e = assert_not_interned_error(Object, :const_get, name)
assert_equal(name, e.name)
assert_not_match(/Object::/, e.message, bug12089)
end

def test_module_const_defined?
cl = Class.new
name = noninterned_name("A")
Expand Down

0 comments on commit 94171da

Please sign in to comment.