opal 1.2.0 → 1.3.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.await.js +6 -0
  3. data/.eslintrc.js +34 -0
  4. data/.github/workflows/build.yml +8 -0
  5. data/.rubocop.yml +9 -0
  6. data/CHANGELOG.md +4 -0
  7. data/README.md +1 -1
  8. data/Rakefile +1 -0
  9. data/UNRELEASED.md +64 -38
  10. data/docs/async.md +109 -0
  11. data/docs/roda-sprockets.md +0 -2
  12. data/exe/opal +2 -0
  13. data/exe/opal-repl +2 -2
  14. data/lib/opal/builder.rb +5 -1
  15. data/lib/opal/builder_processors.rb +7 -2
  16. data/lib/opal/cache/file_cache.rb +119 -0
  17. data/lib/opal/cache.rb +71 -0
  18. data/lib/opal/cli.rb +35 -1
  19. data/lib/opal/cli_options.rb +21 -0
  20. data/lib/opal/cli_runners/chrome.rb +21 -14
  21. data/lib/opal/cli_runners/chrome_cdp_interface.js +30285 -0
  22. data/lib/opal/cli_runners/{chrome.js → chrome_cdp_interface.rb} +27 -6
  23. data/lib/opal/cli_runners/compiler.rb +2 -1
  24. data/lib/opal/cli_runners/gjs.rb +27 -0
  25. data/lib/opal/cli_runners/mini_racer.rb +36 -0
  26. data/lib/opal/cli_runners/source-map-support-browser.js +276 -91
  27. data/lib/opal/cli_runners/source-map-support-node.js +276 -91
  28. data/lib/opal/cli_runners/source-map-support.js +60 -18
  29. data/lib/opal/cli_runners.rb +2 -0
  30. data/lib/opal/compiler.rb +99 -10
  31. data/lib/opal/fragment.rb +77 -14
  32. data/lib/opal/nodes/args/extract_kwrestarg.rb +6 -4
  33. data/lib/opal/nodes/args/extract_restarg.rb +10 -12
  34. data/lib/opal/nodes/args.rb +28 -0
  35. data/lib/opal/nodes/base.rb +29 -5
  36. data/lib/opal/nodes/call.rb +123 -2
  37. data/lib/opal/nodes/case.rb +7 -1
  38. data/lib/opal/nodes/class.rb +12 -2
  39. data/lib/opal/nodes/def.rb +3 -23
  40. data/lib/opal/nodes/definitions.rb +21 -4
  41. data/lib/opal/nodes/helpers.rb +2 -2
  42. data/lib/opal/nodes/if.rb +39 -9
  43. data/lib/opal/nodes/iter.rb +15 -3
  44. data/lib/opal/nodes/lambda.rb +3 -1
  45. data/lib/opal/nodes/literal.rb +13 -7
  46. data/lib/opal/nodes/logic.rb +2 -2
  47. data/lib/opal/nodes/module.rb +12 -2
  48. data/lib/opal/nodes/rescue.rb +59 -34
  49. data/lib/opal/nodes/scope.rb +88 -6
  50. data/lib/opal/nodes/super.rb +52 -25
  51. data/lib/opal/nodes/top.rb +13 -7
  52. data/lib/opal/nodes/while.rb +7 -1
  53. data/lib/opal/parser/patch.rb +2 -1
  54. data/lib/opal/repl.rb +137 -49
  55. data/lib/opal/rewriters/binary_operator_assignment.rb +10 -10
  56. data/lib/opal/rewriters/block_to_iter.rb +3 -3
  57. data/lib/opal/rewriters/for_rewriter.rb +7 -7
  58. data/lib/opal/rewriters/js_reserved_words.rb +5 -3
  59. data/lib/opal/source_map/file.rb +7 -4
  60. data/lib/opal/source_map/map.rb +17 -3
  61. data/lib/opal/version.rb +1 -1
  62. data/opal/corelib/array.rb +2 -2
  63. data/opal/corelib/binding.rb +46 -0
  64. data/opal/corelib/boolean.rb +54 -4
  65. data/opal/corelib/class.rb +2 -0
  66. data/opal/corelib/constants.rb +2 -2
  67. data/opal/corelib/error.rb +98 -12
  68. data/opal/corelib/io.rb +250 -38
  69. data/opal/corelib/kernel/format.rb +5 -2
  70. data/opal/corelib/kernel.rb +44 -23
  71. data/opal/corelib/main.rb +5 -0
  72. data/opal/corelib/method.rb +1 -0
  73. data/opal/corelib/module.rb +28 -0
  74. data/opal/corelib/number.rb +12 -1
  75. data/opal/corelib/random/seedrandom.js.rb +2 -2
  76. data/opal/corelib/regexp.rb +47 -3
  77. data/opal/corelib/runtime.js +152 -12
  78. data/opal/corelib/string/encoding.rb +17 -17
  79. data/opal/corelib/string.rb +2 -0
  80. data/opal/corelib/struct.rb +10 -3
  81. data/opal/corelib/trace_point.rb +57 -0
  82. data/opal/opal/full.rb +2 -0
  83. data/package.json +3 -2
  84. data/spec/filters/bugs/array.rb +0 -1
  85. data/spec/filters/bugs/basicobject.rb +0 -1
  86. data/spec/filters/bugs/binding.rb +27 -0
  87. data/spec/filters/bugs/enumerator.rb +132 -0
  88. data/spec/filters/bugs/exception.rb +70 -93
  89. data/spec/filters/bugs/float.rb +0 -1
  90. data/spec/filters/bugs/kernel.rb +3 -9
  91. data/spec/filters/bugs/language.rb +15 -58
  92. data/spec/filters/bugs/main.rb +16 -0
  93. data/spec/filters/bugs/matrix.rb +39 -0
  94. data/spec/filters/bugs/method.rb +0 -2
  95. data/spec/filters/bugs/module.rb +36 -79
  96. data/spec/filters/bugs/proc.rb +0 -1
  97. data/spec/filters/bugs/regexp.rb +0 -16
  98. data/spec/filters/bugs/trace_point.rb +12 -0
  99. data/spec/filters/bugs/warnings.rb +0 -4
  100. data/spec/filters/unsupported/freeze.rb +2 -0
  101. data/spec/filters/unsupported/privacy.rb +4 -0
  102. data/spec/lib/compiler_spec.rb +7 -1
  103. data/spec/lib/repl_spec.rb +4 -2
  104. data/spec/lib/source_map/file_spec.rb +1 -1
  105. data/spec/mspec-opal/formatters.rb +18 -4
  106. data/spec/mspec-opal/runner.rb +2 -2
  107. data/spec/opal/core/boolean_spec.rb +44 -0
  108. data/spec/opal/core/hash_spec.rb +8 -0
  109. data/spec/opal/core/number/to_s_spec.rb +11 -0
  110. data/spec/opal/stdlib/json/ext_spec.rb +3 -3
  111. data/spec/opal/stdlib/logger/logger_spec.rb +10 -1
  112. data/spec/ruby_specs +18 -0
  113. data/stdlib/await.rb +83 -0
  114. data/stdlib/base64.rb +4 -4
  115. data/stdlib/bigdecimal/bignumber.js.rb +4 -2
  116. data/stdlib/bigdecimal.rb +1 -0
  117. data/stdlib/gjs/io.rb +33 -0
  118. data/stdlib/gjs/kernel.rb +5 -0
  119. data/stdlib/gjs.rb +2 -0
  120. data/stdlib/js.rb +4 -0
  121. data/stdlib/json.rb +3 -3
  122. data/stdlib/logger.rb +1 -1
  123. data/stdlib/nashorn/file.rb +2 -0
  124. data/stdlib/nodejs/env.rb +7 -0
  125. data/stdlib/nodejs/file.rb +6 -41
  126. data/stdlib/nodejs/io.rb +21 -5
  127. data/stdlib/nodejs/js-yaml-3-6-1.js +2 -2
  128. data/stdlib/opal/miniracer.rb +6 -0
  129. data/stdlib/opal/platform.rb +4 -0
  130. data/stdlib/opal/repl_js.rb +5 -0
  131. data/stdlib/opal/replutils.rb +271 -0
  132. data/stdlib/opal-parser.rb +24 -11
  133. data/stdlib/opal-platform.rb +8 -0
  134. data/stdlib/promise/v2.rb +16 -4
  135. data/stdlib/promise.rb +14 -0
  136. data/stdlib/stringio.rb +13 -110
  137. data/stdlib/thread.rb +29 -0
  138. data/tasks/building.rake +10 -4
  139. data/tasks/linting-parse-eslint-results.js +39 -0
  140. data/tasks/linting.rake +38 -28
  141. data/tasks/performance/asciidoctor_test.rb.erb +6 -0
  142. data/tasks/performance/optimization_status.rb +77 -0
  143. data/tasks/performance.rake +149 -0
  144. data/tasks/testing.rake +9 -1
  145. data/test/nodejs/test_await.rb +169 -0
  146. data/test/opal/promisev2/test_error.rb +9 -3
  147. data/test/opal/unsupported_and_bugs.rb +5 -0
  148. data/vendored-minitest/minitest/benchmark.rb +9 -7
  149. data/vendored-minitest/minitest/test.rb +14 -12
  150. data/vendored-minitest/minitest.rb +19 -16
  151. data/yarn.lock +686 -117
  152. metadata +60 -23
  153. data/.jshintrc +0 -41
  154. data/spec/filters/unsupported/refinements.rb +0 -8
  155. data/vendored-minitest/minitest/hell.rb +0 -11
  156. data/vendored-minitest/minitest/parallel.rb +0 -65
  157. data/vendored-minitest/minitest/pride.rb +0 -4
  158. data/vendored-minitest/minitest/pride_plugin.rb +0 -142
  159. data/vendored-minitest/minitest/unit.rb +0 -45
data/tasks/linting.rake CHANGED
@@ -1,42 +1,52 @@
1
1
  import 'tasks/building.rake'
2
- desc "Build *corelib* and *stdlib* and lint the result"
3
- task :jshint do
4
- dir = 'tmp/lint'
5
- puts
6
- puts "= Checking distributed files..."
7
- unless ENV['SKIP_BUILD']
2
+
3
+
4
+ namespace :lint do
5
+ desc "Build *corelib* and *stdlib* and lint the result"
6
+ task :eslint do
7
+ require 'json'
8
+ require 'pathname'
9
+
10
+ result_path = "tmp/lint/result.json"
11
+ dir = ENV['DIR'] ||= 'tmp/lint'
12
+ ENV['FORMATS'] = 'js,map'
8
13
  rm_rf dir if File.exist? dir
9
- ENV['DIR'] = dir
14
+
10
15
  Rake::Task[:dist].invoke
11
- end
12
16
 
13
- Dir["#{dir}/*.js"].each {|path|
14
- # opal-builder and opal-parser take so long travis stalls
15
- next if path =~ /.min.js\z|opal-builder|opal-parser/
16
-
17
- sh "yarn -s run jshint --verbose #{path}"
18
- }
19
- puts
20
- puts "= Checking corelib files separately..."
21
- js_paths = []
22
- Dir['opal/{opal,corelib}/*.rb'].each do |path|
23
- js_path = "#{dir}/#{path.tr('/', '-')}.js"
24
- Bundler::SharedHelpers.set_bundle_environment
25
- File.write js_path, Opal.compile(File.read(path), file: path, dynamic_require_severity: :ignore)
26
- js_paths << js_path
27
- end
28
- js_paths.each do |js_path|
29
- sh "yarn -s run jshint --verbose #{js_path}"
17
+ files = Dir["#{dir}/*.js"]
18
+ es8, es3 = files.partition { |i| i.include? "await" }
19
+
20
+ [es3, es8].each do |files|
21
+ config = (files == es8) ? ["-c", __dir__+"/../.eslintrc.await.js"] : []
22
+
23
+ sh "yarn", "run", "eslint", *config, *files, "--format", "json", "--output-file", result_path do |ok, _|
24
+ if ok
25
+ puts "Successful."
26
+ else
27
+ sh 'node tasks/linting-parse-eslint-results.js'
28
+ # results = JSON.parse File.read(result_path), symbolize_names: true
29
+ # results.each do |data|
30
+ # next if data[:messages].empty?
31
+ #
32
+ # relative_path = Pathname(data[:filePath]).relative_path_from(Pathname(dir).expand_path)
33
+ # puts "* #{relative_path}"
34
+ # data[:messages].each do |message|
35
+ # puts " - #{relative_path}:#{message[:line]}:#{message[:column]}-#{message[:endLine]}:#{message[:endColumn]} #{message[:message]}"
36
+ # end
37
+ # end
38
+ end
39
+ end
40
+ end
30
41
  end
31
- sh 'yarn -s run jshint --verbose opal/corelib/runtime.js'
32
42
  end
33
43
 
34
44
  require 'rubocop/rake_task'
35
45
  desc 'Run RuboCop on lib/, opal/ and stdlib/ directories'
36
- RuboCop::RakeTask.new(:rubocop) do |task|
46
+ RuboCop::RakeTask.new('lint:rubocop') do |task|
37
47
  task.options << '--extra-details'
38
48
  task.options << '--display-style-guide'
39
49
  task.options << '--parallel'
40
50
  end
41
51
 
42
- task :lint => [:jshint, :rubocop]
52
+ task :lint => %w[lint:eslint lint:rubocop]
@@ -0,0 +1,6 @@
1
+ JAVASCRIPT_IO_MODULE="nodejs" if RUBY_ENGINE == 'opal'
2
+ require "asciidoctor"
3
+ puts Asciidoctor.convert(DATA.read)
4
+
5
+ __END__
6
+ <%= File.read('asciidoctor/benchmark/sample-data/mdbasics.adoc') %>
@@ -0,0 +1,77 @@
1
+ klasses = [
2
+ Array,
3
+ Class,
4
+ # Complex,
5
+ # Dir,
6
+ Enumerable,
7
+ Enumerator,
8
+ Exception,
9
+ Hash,
10
+ # Kernel,
11
+ Math,
12
+ Method,
13
+ Module,
14
+ Object,
15
+ Proc,
16
+ Range,
17
+ Rational,
18
+ Regexp,
19
+ Struct,
20
+ String,
21
+ Time
22
+ ]
23
+
24
+ %x{
25
+ function getOptimizationStatus(fn) {
26
+ var optstatus = %GetOptimizationStatus(fn);
27
+
28
+ return (optstatus & (1 << 6)) ? "[INTERPRETED]" : "[COMPILED]";
29
+ }
30
+
31
+ function triggerOptAndGetStatus(fn) {
32
+ // using try/catch to avoid having to call functions properly
33
+ try {
34
+ // Fill type-info
35
+ fn();
36
+ // 2 calls are needed to go from uninitialized -> pre-monomorphic -> monomorphic
37
+ fn();
38
+ }
39
+ catch (e) {}
40
+ %OptimizeFunctionOnNextCall(fn);
41
+ try {
42
+ fn();
43
+ }
44
+ catch (e) {}
45
+ return getOptimizationStatus(fn);
46
+ }
47
+ }
48
+
49
+ optimization_status = Hash[klasses.map do |klass|
50
+ methods = klass.instance_methods
51
+ methods -= Object.instance_methods unless klass == Object
52
+ methods -= [:product, :exit, :exit!, :at_exit]
53
+ opt_status = Hash[methods.map do |method|
54
+ method_func = `#{klass.instance_method(method)}.method`
55
+ [method, `triggerOptAndGetStatus(#{method_func})`]
56
+ end]
57
+ by_status_grouped = opt_status.group_by {|method, status| status }
58
+ as_hash = Hash[by_status_grouped.map do |status, stuff|
59
+ list = stuff.map {|val| val[0]}
60
+ [status, list]
61
+ end]
62
+ [klass, as_hash]
63
+ end]
64
+
65
+ puts '----Report----'
66
+ optimization_status.sort_by {|klass,_| klass.name}.each do |klass, statuses|
67
+ puts "---------------"
68
+ puts "Class #{klass}:"
69
+ puts "---------------"
70
+ statuses.sort_by {|stat,_| stat }.each do |status, methods|
71
+ methods.sort.each do |m|
72
+ puts " #{status} #{m}"
73
+ end
74
+ end
75
+ end
76
+
77
+ puts 'done!'
@@ -0,0 +1,149 @@
1
+ # A set of tasks to track performance regressions by the CI
2
+
3
+ require 'opal/util'
4
+
5
+ # Runs a block N times and returns a mean number of seconds it took to run it.
6
+ mean_time = proc do |tries: 31, &block|
7
+ tries.times.map do
8
+ t = Time.now
9
+ block.()
10
+ Time.now - t
11
+ end.sort[tries/2]
12
+ end
13
+
14
+ failed = false
15
+
16
+ # Mark a failure
17
+ failure = proc do |reason|
18
+ failed ||= []
19
+ failed << reason
20
+ end
21
+
22
+ compare_values = proc do |name, current, previous|
23
+ current = current.to_f
24
+ previous = previous.to_f
25
+
26
+ change = ((current - previous).to_f / previous) * 100
27
+
28
+ puts ("%30s: %.3f -> %.3f (change: %+.2f%%)" % [name, previous, current, change]).gsub('.000','')
29
+
30
+ if change > 5.0
31
+ failure.("#{name} increased by more than 5%")
32
+ end
33
+ end
34
+
35
+ ASCIIDOCTOR_REPO_BASE = ENV['ASCIIDOCTOR_REPO_BASE'] || 'https://github.com/asciidoctor'
36
+
37
+ # Selected asciidoctor versions were working on Aug 19 2021, feel free to update.
38
+ ASCIIDOCTOR_PREPARE = [
39
+ "bundle",
40
+ "exec",
41
+ "bash",
42
+ "-c",
43
+ <<~BASH
44
+ mkdir -p tmp/performance
45
+ pushd tmp/performance
46
+ git clone #{ASCIIDOCTOR_REPO_BASE}/asciidoctor >/dev/null 2>&1
47
+ pushd asciidoctor; git checkout 869e8236 >/dev/null 2>&1; popd
48
+ git clone #{ASCIIDOCTOR_REPO_BASE}/asciidoctor.js >/dev/null 2>&1
49
+ pushd asciidoctor.js; git checkout 053fa0d3 >/dev/null 2>&1; popd
50
+ erb ../../tasks/performance/asciidoctor_test.rb.erb > asciidoctor_test.rb
51
+ popd
52
+ BASH
53
+ ]
54
+
55
+ ASCIIDOCTOR_BUILD_OPAL = "bin/opal --no-cache -c " \
56
+ "-Itmp/performance/asciidoctor/lib " \
57
+ "-Itmp/performance/asciidoctor.js/packages/core/lib " \
58
+ "tmp/performance/asciidoctor_test.rb > tmp/performance/asciidoctor_test.js"
59
+ ASCIIDOCTOR_RUN_RUBY = "bundle exec ruby -Itmp/performance/asciidoctor/lib tmp/performance/asciidoctor_test.rb"
60
+ ASCIIDOCTOR_RUN_OPAL = "node tmp/performance/asciidoctor_test.js"
61
+
62
+ # Generate V8 function optimization status report for corelib methods
63
+ NODE_OPTSTATUS = "env NODE_OPTS=--allow-natives-syntax bin/opal tasks/performance/optimization_status.rb"
64
+
65
+ performance_stat = ->(name) {
66
+ stat = {}
67
+
68
+ # Run on current
69
+ puts "\n* Checking optimization status with #{name}..."
70
+ sh("#{NODE_OPTSTATUS} > tmp/performance/optstatus_#{name}")
71
+
72
+ puts "\n* Building AsciiDoctor with #{name}..."
73
+ stat[:compiler_time] = mean_time.(tries: 3) { sh(ASCIIDOCTOR_BUILD_OPAL) }
74
+
75
+ puts "\n* Running AsciiDoctor with #{name}..."
76
+ stat[:run_time] = mean_time.(tries: 31) { sh("#{ASCIIDOCTOR_RUN_OPAL} > tmp/performance/opal_result_#{name}.html") }
77
+ stat[:correct] = File.read("tmp/performance/opal_result_#{name}.html") == File.read("tmp/performance/ruby_result.html")
78
+ stat[:size] = File.size("tmp/performance/asciidoctor_test.js")
79
+
80
+ puts "\n* Minifying AsciiDoctor with #{name}..."
81
+ stat[:min_size] = Opal::Util.uglify(File.read("tmp/performance/asciidoctor_test.js")).bytesize rescue Float::INFINITY
82
+
83
+ stat
84
+ }
85
+
86
+ namespace :performance do
87
+ task :compare do
88
+ this_ref = `git describe --tags`.chomp
89
+ ref = 'master'
90
+ ref = ENV['GITHUB_BASE_REF'] if ENV['GITHUB_BASE_REF'] && !ENV['GITHUB_BASE_REF'].empty?
91
+
92
+ # Prepare
93
+ puts "\n* Preparing asciidoctor..."
94
+ sh(*ASCIIDOCTOR_PREPARE)
95
+
96
+ puts "\n* Running AsciiDoctor with CRuby..."
97
+ sh("#{ASCIIDOCTOR_RUN_RUBY} > tmp/performance/ruby_result.html")
98
+
99
+ current = performance_stat.(:current)
100
+
101
+ # Prepare previous
102
+ sh("git checkout --recurse-submodules #{ref} && bundle install >/dev/null 2>&1")
103
+
104
+ previous = performance_stat.(:previous)
105
+
106
+ # Restore current
107
+ sh("git checkout --recurse-submodules - && bundle install >/dev/null 2>&1")
108
+
109
+ # Summary
110
+ puts "\n=== Summary ==="
111
+ puts "Summary of performance changes between (previous) #{ref} and (current) #{this_ref}:"
112
+
113
+ diff = `diff --report-identical-files -F '^Class' -Naur tmp/performance/optstatus_previous tmp/performance/optstatus_current`
114
+ diff_lines = diff.split("\n")
115
+
116
+ puts
117
+ puts "Comparison of V8 function optimization status:"
118
+ puts diff
119
+
120
+ if diff_lines.grep(/^-\s+\[COMPILED\]/).count > 0
121
+ failure.("Some methods are no longer compiled on V8")
122
+ end
123
+
124
+ puts
125
+ puts "Comparison of the Asciidoctor (a real-life Opal application) compile and run:"
126
+
127
+ failure.("Wrong result on the current branch") unless current[:correct]
128
+ failure.("Wrong result on the previous branch - ignore it") unless previous[:correct]
129
+
130
+ compare_values.("Compile time", current[:compiler_time], previous[:compiler_time])
131
+ compare_values.("Run time", current[:run_time], previous[:run_time])
132
+ compare_values.("Bundle size", current[:size], previous[:size])
133
+ compare_values.("Minified bundle size", current[:min_size], previous[:min_size])
134
+
135
+ if failed
136
+ puts "--- Failures ---"
137
+ failed.each do |f|
138
+ puts " - #{f}"
139
+ end
140
+ puts
141
+ puts "This run failed - some performance checks did not pass. Don't worry, this is"
142
+ puts "informative, not fatal. It may be worth to rerun the task, rebase the branch,"
143
+ puts "or consult those results with a pull request reviewer."
144
+ fail
145
+ end
146
+ end
147
+ end
148
+
149
+ task :performance => ['performance:compare']
data/tasks/testing.rake CHANGED
@@ -284,7 +284,7 @@ Use PATTERN environment variable to manually set the glob for specs:
284
284
  bundle exec rake mspec_nodejs PATTERN=spec/ruby/core/numeric/**_spec.rb
285
285
  DESC
286
286
 
287
- platforms = %w[nodejs server chrome]
287
+ platforms = %w[nodejs server chrome gjs]
288
288
  mspec_suites = %w[ruby opal]
289
289
  minitest_suites = %w[cruby]
290
290
 
@@ -331,6 +331,13 @@ platforms.each do |platform|
331
331
  opal/test_openuri.rb
332
332
  opal/unsupported_and_bugs.rb
333
333
  opal/test_matrix.rb
334
+ opal/promisev2/test_always.rb
335
+ opal/promisev2/test_error.rb
336
+ opal/promisev2/test_rescue.rb
337
+ opal/promisev2/test_then.rb
338
+ opal/promisev2/test_trace.rb
339
+ opal/promisev2/test_value.rb
340
+ opal/promisev2/test_when.rb
334
341
  ]
335
342
  end
336
343
  Testing::HTTPServer.new.with_server do |session|
@@ -363,6 +370,7 @@ task :minitest_node_nodejs do
363
370
  nodejs/test_io.rb
364
371
  nodejs/test_opal_builder.rb
365
372
  nodejs/test_string.rb
373
+ nodejs/test_await.rb
366
374
  ]
367
375
 
368
376
  filename = "tmp/minitest_node_nodejs.rb"
@@ -0,0 +1,169 @@
1
+ # frozen_string_literal: true
2
+ # await: true
3
+
4
+ require "test/unit"
5
+
6
+ class TestAwait < Test::Unit::TestCase
7
+ stdheader = <<~RUBY
8
+ # await: true
9
+ require "await"
10
+ RUBY
11
+
12
+ tests = {
13
+ test_await_in_top: [<<~RUBY, 6],
14
+ #{stdheader}
15
+ $taval = 5
16
+ sleep(0.001).__await__
17
+ $taval = 6
18
+ RUBY
19
+ test_await_in_method: [<<~RUBY, 7],
20
+ #{stdheader}
21
+ $taval = 5
22
+ def xx_taim
23
+ sleep(0.001).__await__
24
+ $taval = 7
25
+ end
26
+ xx_taim.__await__
27
+ RUBY
28
+ test_await_in_block: [<<~RUBY, 0],
29
+ #{stdheader}
30
+ $taval = 5
31
+ xx_taib = proc do
32
+ sleep(0.001).__await__
33
+ $taval = 0
34
+ end
35
+ xx_taib.().__await__
36
+ RUBY
37
+ test_await_in_instance_method: [<<~RUBY, 3],
38
+ #{stdheader}
39
+ $taval = 5
40
+ class XXTaiim
41
+ def xx_taiim
42
+ sleep(0.001).__await__
43
+ $taval = 3
44
+ end
45
+ end
46
+ XXTaiim.new.xx_taiim.__await__
47
+ RUBY
48
+ test_await_in_class_method: [<<~RUBY, 4],
49
+ #{stdheader}
50
+ $taval = 5
51
+ class XXTaicm
52
+ def self.xx_taicm
53
+ sleep(0.001).__await__
54
+ $taval = 4
55
+ end
56
+ end
57
+ XXTaicm.xx_taicm.__await__
58
+ RUBY
59
+ test_await_on_promise: [<<~RUBY, 8],
60
+ #{stdheader}
61
+ $taval = PromiseV2.value(8).__await__
62
+ RUBY
63
+ test_await_in_while: [<<~RUBY, 9],
64
+ #{stdheader}
65
+ $taval = 5
66
+ begin
67
+ sleep(0.001).__await__
68
+ $taval = 9
69
+ end while false
70
+ RUBY
71
+ test_await_in_while_expr: [<<~RUBY, -9],
72
+ #{stdheader}
73
+ $taval = 5
74
+ x = if true
75
+ begin
76
+ sleep(0.001).__await__
77
+ $taval = -9
78
+ end while false
79
+ end
80
+ RUBY
81
+ test_await_in_case: [<<~RUBY, 88],
82
+ #{stdheader}
83
+ $taval = 5
84
+ case true
85
+ when true
86
+ sleep(0.001).__await__
87
+ $taval = 88
88
+ end
89
+ RUBY
90
+ test_await_in_case_expr: [<<~RUBY, 99],
91
+ #{stdheader}
92
+ $taval = 5
93
+ x = case true
94
+ when true
95
+ sleep(0.001).__await__
96
+ $taval = 99
97
+ end
98
+ RUBY
99
+ test_await_in_rescue: [<<~RUBY, 10],
100
+ #{stdheader}
101
+ $taval = 5
102
+ begin
103
+ sleep(0.001).__await__
104
+ nomethoderror
105
+ rescue
106
+ sleep(0.001).__await__
107
+ $taval = 10
108
+ end
109
+ RUBY
110
+ test_await_in_ensure: [<<~RUBY, 11],
111
+ #{stdheader}
112
+ $taval = 5
113
+ begin
114
+ sleep(0.001).__await__
115
+ nomethoderror
116
+ rescue
117
+ sleep(0.001).__await__
118
+ ensure
119
+ sleep(0.001).__await__
120
+ $taval = 11
121
+ end
122
+ RUBY
123
+ test_await_in_ensure_expr: [<<~RUBY, -11],
124
+ #{stdheader}
125
+ $taval = 5
126
+ x = begin
127
+ sleep(0.001).__await__
128
+ nomethoderror
129
+ rescue
130
+ sleep(0.001).__await__
131
+ ensure
132
+ sleep(0.001).__await__
133
+ $taval = -11
134
+ end
135
+ RUBY
136
+ test_await_in_module: [<<~RUBY, 12],
137
+ #{stdheader}
138
+ $taval = 5
139
+ module XYTaim
140
+ sleep(0.001).__await__
141
+ $taval = 12
142
+ end
143
+ RUBY
144
+ test_await_in_class: [<<~RUBY, 13],
145
+ #{stdheader}
146
+ $taval = 5
147
+ class XYTaic
148
+ sleep(0.001).__await__
149
+ $taval = 13
150
+ end
151
+ RUBY
152
+ test_await_in_and: [<<~RUBY, 14],
153
+ #{stdheader}
154
+ ($taval = 5) && (PromiseV2.value(4).__await__) && ($taval = 14)
155
+ RUBY
156
+ test_await_in_plus: [<<~RUBY, 15],
157
+ #{stdheader}
158
+ $taval = 5
159
+ $taval = PromiseV2.value(5).__await__ + 10
160
+ RUBY
161
+ }
162
+
163
+ tests.each do |name,(code,expect)|
164
+ define_method name do
165
+ eval(code).__await__
166
+ assert_equal(expect, $taval)
167
+ end
168
+ end
169
+ end
@@ -3,14 +3,20 @@ require 'promise/v2'
3
3
 
4
4
  class TestPromiseError < Test::Unit::TestCase
5
5
  def test_rejects_the_promise_with_the_given_error
6
- assert_equal(PromiseV2.error(23).error, 23)
6
+ prom = PromiseV2.error(23)
7
+ assert_equal(prom.error, 23)
8
+ prom.rescue{} # Needed, otherwise we have an uncaught exception
7
9
  end
8
10
 
9
11
  def test_marks_the_promise_as_realized
10
- assert_equal(PromiseV2.error(23).realized?, true)
12
+ prom = PromiseV2.error(23)
13
+ assert_equal(prom.realized?, true)
14
+ prom.rescue{} # Needed, otherwise we have an uncaught exception
11
15
  end
12
16
 
13
17
  def test_marks_the_promise_as_rejected
14
- assert_equal(PromiseV2.error(23).rejected?, true)
18
+ prom = PromiseV2.error(23)
19
+ assert_equal(prom.rejected?, true)
20
+ prom.rescue{}
15
21
  end
16
22
  end
@@ -37,3 +37,8 @@ class TestCall
37
37
  unsupported :test_safe_call_block_call_brace
38
38
  unsupported :test_safe_call_block_call_command
39
39
  end
40
+
41
+ class TestBenchmark
42
+ # sleep is unsupported if not awaited
43
+ unsupported :test_realtime_output
44
+ end
@@ -1,3 +1,5 @@
1
+ # await: *await*
2
+
1
3
  require 'minitest/unit'
2
4
  require 'minitest/spec'
3
5
 
@@ -88,10 +90,10 @@ module Minitest
88
90
 
89
91
  times = []
90
92
 
91
- range.each do |x|
93
+ range.each_await do |x|
92
94
  GC.start
93
95
  t0 = Time.now
94
- instance_exec(x, &work)
96
+ instance_exec(x, &work).await
95
97
  t = Time.now - t0
96
98
 
97
99
  io.print "\t%9.6f" % t
@@ -132,7 +134,7 @@ module Minitest
132
134
  [a, b, rr]
133
135
  end
134
136
 
135
- assert_performance validation, &work
137
+ assert_performance(validation, &work).await
136
138
  end
137
139
 
138
140
  ##
@@ -152,7 +154,7 @@ module Minitest
152
154
  # end
153
155
 
154
156
  def assert_performance_exponential threshold = 0.99, &work
155
- assert_performance validation_for_fit(:exponential, threshold), &work
157
+ assert_performance(validation_for_fit(:exponential, threshold), &work).await
156
158
  end
157
159
 
158
160
  ##
@@ -172,7 +174,7 @@ module Minitest
172
174
  # end
173
175
 
174
176
  def assert_performance_logarithmic threshold = 0.99, &work
175
- assert_performance validation_for_fit(:logarithmic, threshold), &work
177
+ assert_performance(validation_for_fit(:logarithmic, threshold), &work).await
176
178
  end
177
179
 
178
180
  ##
@@ -192,7 +194,7 @@ module Minitest
192
194
  # end
193
195
 
194
196
  def assert_performance_linear threshold = 0.99, &work
195
- assert_performance validation_for_fit(:linear, threshold), &work
197
+ assert_performance(validation_for_fit(:linear, threshold), &work).await
196
198
  end
197
199
 
198
200
  ##
@@ -212,7 +214,7 @@ module Minitest
212
214
  # end
213
215
 
214
216
  def assert_performance_power threshold = 0.99, &work
215
- assert_performance validation_for_fit(:power, threshold), &work
217
+ assert_performance(validation_for_fit(:power, threshold), &work).await
216
218
  end
217
219
 
218
220
  ##
@@ -1,3 +1,5 @@
1
+ # await: *await*
2
+
1
3
  require "minitest" unless defined? Minitest::Runnable
2
4
 
3
5
  module Minitest
@@ -105,16 +107,16 @@ module Minitest
105
107
  capture_exceptions do
106
108
  before_setup; setup; after_setup
107
109
 
108
- self.send self.name
109
- end
110
+ self.send(self.name).await
111
+ end.await
110
112
 
111
- TEARDOWN_METHODS.each do |hook|
113
+ TEARDOWN_METHODS.each_await do |hook|
112
114
  capture_exceptions do
113
- self.send hook
114
- end
115
- end
116
- end
117
- end
115
+ self.send(hook).await
116
+ end.await
117
+ end.await
118
+ end.await
119
+ end.await
118
120
 
119
121
  self # per contract
120
122
  end
@@ -202,7 +204,7 @@ module Minitest
202
204
  end # LifecycleHooks
203
205
 
204
206
  def capture_exceptions # :nodoc:
205
- yield
207
+ yield.await
206
208
  rescue *PASSTHROUGH_EXCEPTIONS
207
209
  raise
208
210
  rescue Assertion => e
@@ -253,7 +255,7 @@ module Minitest
253
255
  def time_it # :nodoc:
254
256
  t0 = Time.now
255
257
 
256
- yield
258
+ yield.await
257
259
  ensure
258
260
  self.time = Time.now - t0
259
261
  end
@@ -273,7 +275,7 @@ module Minitest
273
275
  warn "\nCurrent: %s#%s %.2fs" % [self.class, self.name, Time.now - t0]
274
276
  end
275
277
 
276
- self.class.on_signal "INFO", handler, &block
278
+ self.class.on_signal("INFO", handler, &block).await
277
279
  end
278
280
 
279
281
  include LifecycleHooks
@@ -282,4 +284,4 @@ module Minitest
282
284
  end # Test
283
285
  end
284
286
 
285
- require "minitest/unit" unless defined?(MiniTest) # compatibility layer only
287
+ # require "minitest/unit" unless defined?(MiniTest) # compatibility layer only