mirah 0.1.2-java → 0.1.3-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/History.txt +225 -0
  3. data/Rakefile +108 -315
  4. data/TODO.md +100 -0
  5. data/bin/bundler +16 -0
  6. data/bin/rake +16 -0
  7. data/dist/mirahc.jar +0 -0
  8. data/examples/appengine/Readme +0 -1
  9. data/examples/literals.mirah +17 -0
  10. data/examples/macros/string_each_char.mirah +1 -1
  11. data/lib/mirah.rb +11 -21
  12. data/lib/mirah/transform/transformer.rb +1 -2
  13. data/lib/mirah/util/class_loader.rb +1 -1
  14. data/lib/mirah/util/logging.rb +0 -63
  15. data/lib/mirah/util/process_errors.rb +1 -0
  16. data/lib/mirah/version.rb +1 -1
  17. data/{examples/simple_class.mirah~ → test/artifacts/jar_test.rb} +7 -11
  18. data/{lib/mirah/commands.rb → test/artifacts/jruby_test.rb} +8 -5
  19. data/test/core/typer_test.rb +29 -11
  20. data/test/core/util/argument_processor_test.rb +24 -23
  21. data/test/core/util/class_loader_test.rb +7 -4
  22. data/test/core/util/{compilation_state_test.rb → jvm_version_test.rb} +20 -16
  23. data/test/fixtures/org/foo/ImplicitClassRetAnno.java +4 -0
  24. data/test/fixtures/org/foo/IntAnno.java +9 -0
  25. data/test/jvm/annotations_test.rb +11 -11
  26. data/test/jvm/blocks_test.rb +16 -12
  27. data/test/jvm/constructors_test.rb +8 -8
  28. data/test/jvm/enumerable_test.rb +48 -24
  29. data/test/jvm/generics_test.rb +3 -7
  30. data/test/jvm/import_test.rb +14 -0
  31. data/test/jvm/interface_test.rb +9 -24
  32. data/test/jvm/jvm_commands_test.rb +22 -4
  33. data/test/jvm/jvm_compiler_test.rb +124 -79
  34. data/test/jvm/list_extensions_test.rb +1 -1
  35. data/test/jvm/macros_test.rb +67 -14
  36. data/test/jvm/main_method_test.rb +1 -1
  37. data/test/jvm/new_backend_test_helper.rb +100 -3
  38. data/{lib/mirah/jvm/types/bitescript_ext.rb → test/jvm/static_fields_test.rb} +22 -21
  39. data/test/mirrors/base_type_test.rb +4 -3
  40. data/test/mirrors/bytecode_mirror_test.rb +35 -15
  41. data/test/mirrors/generics_test.rb +14 -5
  42. data/test/mirrors/member_test.rb +2 -1
  43. data/test/mirrors/method_lookup_test.rb +18 -6
  44. data/test/mirrors/mirrors_test.rb +87 -20
  45. data/test/mirrors/simple_async_mirror_loader_test.rb +7 -3
  46. data/test/mirrors/simple_mirror_loader_test.rb +5 -5
  47. data/test/test_helper.rb +25 -1
  48. metadata +18 -78
  49. data/bin/mirahp +0 -27
  50. data/bin/mirahp.cmd +0 -16
  51. data/examples/Fib.class +0 -0
  52. data/javalib/mirah-bootstrap.jar +0 -0
  53. data/javalib/mirah-builtins.jar +0 -0
  54. data/javalib/mirah-compiler.jar +0 -0
  55. data/javalib/mirah-mirrors.jar +0 -0
  56. data/javalib/mirah-newast-transitional.jar +0 -0
  57. data/javalib/mirah-parser.jar +0 -0
  58. data/javalib/mirah-util.jar +0 -0
  59. data/lib/mirah/ast.rb +0 -43
  60. data/lib/mirah/ast/scope.rb +0 -262
  61. data/lib/mirah/commands/base.rb +0 -59
  62. data/lib/mirah/commands/compile.rb +0 -39
  63. data/lib/mirah/commands/parse.rb +0 -36
  64. data/lib/mirah/commands/run.rb +0 -78
  65. data/lib/mirah/generator.rb +0 -150
  66. data/lib/mirah/jvm/compiler.rb +0 -50
  67. data/lib/mirah/jvm/compiler/base.rb +0 -421
  68. data/lib/mirah/jvm/compiler/jvm_bytecode.rb +0 -1194
  69. data/lib/mirah/jvm/method_lookup.rb +0 -307
  70. data/lib/mirah/jvm/types.rb +0 -45
  71. data/lib/mirah/jvm/types/array_type.rb +0 -60
  72. data/lib/mirah/jvm/types/ast_ext.rb +0 -31
  73. data/lib/mirah/jvm/types/basic_types.rb +0 -41
  74. data/lib/mirah/jvm/types/block_type.rb +0 -15
  75. data/lib/mirah/jvm/types/boolean.rb +0 -70
  76. data/lib/mirah/jvm/types/enumerable.rb +0 -80
  77. data/lib/mirah/jvm/types/extensions.rb +0 -110
  78. data/lib/mirah/jvm/types/factory.rb +0 -830
  79. data/lib/mirah/jvm/types/floats.rb +0 -99
  80. data/lib/mirah/jvm/types/generic_type.rb +0 -72
  81. data/lib/mirah/jvm/types/implicit_nil_type.rb +0 -29
  82. data/lib/mirah/jvm/types/integers.rb +0 -131
  83. data/lib/mirah/jvm/types/interface_definition.rb +0 -20
  84. data/lib/mirah/jvm/types/intrinsics.rb +0 -385
  85. data/lib/mirah/jvm/types/literals.rb +0 -89
  86. data/lib/mirah/jvm/types/meta_type.rb +0 -54
  87. data/lib/mirah/jvm/types/methods.rb +0 -946
  88. data/lib/mirah/jvm/types/null_type.rb +0 -39
  89. data/lib/mirah/jvm/types/number.rb +0 -184
  90. data/lib/mirah/jvm/types/primitive_type.rb +0 -76
  91. data/lib/mirah/jvm/types/source_mirror.rb +0 -274
  92. data/lib/mirah/jvm/types/type.rb +0 -311
  93. data/lib/mirah/jvm/types/type_definition.rb +0 -72
  94. data/lib/mirah/jvm/types/void_type.rb +0 -19
  95. data/lib/mirah/util/compilation_state.rb +0 -60
  96. data/test/core/commands_test.rb +0 -89
  97. data/test/core/generator_test.rb +0 -26
  98. data/test/fixtures/org/foo/LowerCaseInnerClass$inner.class +0 -0
  99. data/test/fixtures/org/foo/LowerCaseInnerClass.class +0 -0
  100. data/test/jvm/bytecode_test_helper.rb +0 -193
  101. data/test/jvm/factory_test.rb +0 -28
  102. data/test/jvm/java_typer_test.rb +0 -283
@@ -11,7 +11,7 @@ class ListExtensionsTest < Test::Unit::TestCase
11
11
 
12
12
  def test_bracket_assignment
13
13
  cls, = compile(<<-EOF)
14
- import java.util.ArrayList # literals are immutable
14
+ import java.util.ArrayList
15
15
  x = ArrayList.new
16
16
  x[0]= "2"
17
17
  puts x
@@ -14,13 +14,49 @@
14
14
  # limitations under the License.
15
15
 
16
16
  class MacrosTest < Test::Unit::TestCase
17
+ #TODO perhaps one of these should be an error
18
+ def test_block_args_no_pipes_macro
19
+ cls, = compile(<<-EOF)
20
+ macro def foo(list: Node, block: Block)
21
+ quote do
22
+ `list`.each do `block.arguments`
23
+ puts 1
24
+ `block.body`
25
+ end
26
+ end
27
+ end
28
+
29
+ foo [2,3] {|x| puts x }
30
+ EOF
31
+
32
+ assert_output("1\n2\n1\n3\n") {cls.main(nil)}
33
+ end
34
+
35
+ def test_block_args_with_pipes_macro
36
+ cls, = compile(<<-EOF)
37
+ macro def foo(list: Node, block: Block)
38
+ quote do
39
+ `list`.each do |`block.arguments`|
40
+ puts 1
41
+ `block.body`
42
+ end
43
+ end
44
+ end
45
+
46
+ foo [2,3] {|x| puts x }
47
+ EOF
48
+
49
+ assert_output("1\n2\n1\n3\n") {cls.main(nil)}
50
+ end
51
+
52
+
17
53
  def test_vcall_macro
18
54
  cls, = compile(<<-EOF)
19
55
  macro def foo
20
56
  mirah::lang::ast::Null.new
21
57
  end
22
58
 
23
- System.out.println(Object(foo))
59
+ puts(Object(foo))
24
60
  EOF
25
61
 
26
62
  assert_output("null\n") {cls.main(nil)}
@@ -48,7 +84,7 @@ class MacrosTest < Test::Unit::TestCase
48
84
  mirah::lang::ast::Null.new
49
85
  end
50
86
 
51
- System.out.println(Object(foo()))
87
+ puts(Object(foo()))
52
88
  EOF
53
89
 
54
90
  assert_output("null\n") {cls.main(nil)}
@@ -61,7 +97,7 @@ class MacrosTest < Test::Unit::TestCase
61
97
  quote { nil }
62
98
  end
63
99
 
64
- System.out.println(Object(foo))
100
+ puts(Object(foo))
65
101
  EOF
66
102
 
67
103
  assert_output("null\n") {cls.main(nil)}
@@ -192,10 +228,11 @@ class MacrosTest < Test::Unit::TestCase
192
228
  end
193
229
 
194
230
  x = UnquoteMacros.new
195
- System.out.println x.foo
231
+ puts x.foo
196
232
  x.foo = 3
197
- System.out.println x.foo
233
+ puts x.foo
198
234
  EOF
235
+
199
236
  assert_output("0\n3\n") {script.main(nil)}
200
237
  end
201
238
 
@@ -213,8 +250,8 @@ class MacrosTest < Test::Unit::TestCase
213
250
 
214
251
  def foo
215
252
  x = "1"
216
- System.out.println doubleIt(x)
217
- System.out.println x
253
+ puts doubleIt(x)
254
+ puts x
218
255
  end
219
256
  EOF
220
257
 
@@ -236,8 +273,8 @@ class MacrosTest < Test::Unit::TestCase
236
273
 
237
274
  def foo
238
275
  x = 1
239
- System.out.println doubleIt(x)
240
- System.out.println x
276
+ puts doubleIt(x)
277
+ puts x
241
278
  end
242
279
  EOF
243
280
 
@@ -251,7 +288,7 @@ class MacrosTest < Test::Unit::TestCase
251
288
  end
252
289
 
253
290
  def bar(a:String, b:String, c:String, d:String)
254
- System.out.println "\#{a} \#{b} \#{c} \#{d}"
291
+ puts "\#{a} \#{b} \#{c} \#{d}"
255
292
  end
256
293
 
257
294
  foo(["a", "b"])
@@ -265,7 +302,7 @@ class MacrosTest < Test::Unit::TestCase
265
302
  def test_block_parameter_uses_outer_scope
266
303
  cls, = compile(<<-EOF)
267
304
  macro def foo(block:Block)
268
- quote { z = `block.body`; System.out.println z }
305
+ quote { z = `block.body`; puts z }
269
306
  end
270
307
  apple = 1
271
308
  foo do
@@ -278,11 +315,27 @@ class MacrosTest < Test::Unit::TestCase
278
315
  end
279
316
  end
280
317
 
318
+
319
+ def test_block_parameter
320
+ cls, = compile(<<-EOF)
321
+ macro def foo(&block)
322
+ block.body
323
+ end
324
+ foo do
325
+ puts :hi
326
+ end
327
+ EOF
328
+
329
+ assert_output("hi\n") do
330
+ cls.main(nil)
331
+ end
332
+ end
333
+
281
334
  def test_method_def_after_macro_def_with_same_name_raises_error
282
335
  assert_raises Mirah::MirahError do
283
336
  compile(<<-EOF)
284
337
  macro def self.foo
285
- quote { System.out.println :z }
338
+ quote { puts :z }
286
339
  end
287
340
  def foo
288
341
  :bar
@@ -314,9 +367,9 @@ class MacrosTest < Test::Unit::TestCase
314
367
  end
315
368
 
316
369
  x = AttrAccessorTest.new
317
- System.out.println x.foo
370
+ puts x.foo
318
371
  x.foo = 3
319
- System.out.println x.foo
372
+ puts x.foo
320
373
  EOF
321
374
  assert_output("0\n3\n") {script.main(nil)}
322
375
  end
@@ -3,7 +3,7 @@ class MainMethodTest < Test::Unit::TestCase
3
3
  code = <<-EOC
4
4
  class WithMain
5
5
  end
6
- System.out.println 'bar'
6
+ puts 'bar'
7
7
  EOC
8
8
 
9
9
  main_class, = compile code, :name => 'with_main'
@@ -12,14 +12,111 @@
12
12
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
- require 'bytecode_test_helper'
15
+ require 'test_helper'
16
16
 
17
17
  module JVMCompiler
18
- def compiler_type
19
- Mirah::JVM::Compiler::Backend
18
+ java_import 'org.mirah.tool.RunCommand'
19
+ java_import 'org.mirah.util.SimpleDiagnostics'
20
+ System = java.lang.System
21
+ JVM_VERSION = ENV['MIRAH_TEST_JVM_VERSION'] || '1.7'
22
+
23
+ class TestDiagnostics < SimpleDiagnostics
24
+ java_import 'java.util.Locale'
25
+ def report(diagnostic)
26
+ if diagnostic.kind.name == "ERROR"
27
+ raise Mirah::MirahError, diagnostic.getMessage(Locale.getDefault)
28
+ end
29
+ super
30
+ end
31
+ end
32
+ def parse_and_resolve_types name, code
33
+ cmd = build_command name, code
34
+ compile_or_raise cmd, ["-d", TEST_DEST]
35
+ cmd.compiler.getParsedNodes[0]
36
+ end
37
+
38
+ def compile(code, options = {})
39
+ name = options.fetch :name, tmp_script_name
40
+
41
+ java_version = options.fetch :java_version, JVMCompiler::JVM_VERSION
42
+ args = ["-d", TEST_DEST,
43
+ "--vmodule", "org.mirah.jvm.compiler.ClassCompiler=OFF",
44
+ "--classpath", Mirah::Env.encode_paths([FIXTURE_TEST_DEST, TEST_DEST]) ]
45
+ if java_version
46
+ args += ["--jvm", java_version]
47
+ end
48
+
49
+ cmd = build_command name, code
50
+ compile_or_raise cmd, args
51
+
52
+ dump_class_files cmd.classMap
53
+
54
+ cmd.loadClasses.map {|cls| JRuby.runtime.java_support.getProxyClassFromCache(cls)}
55
+ end
56
+
57
+ def build_command(name, code)
58
+ cmd = RunCommand.new
59
+ cmd.addFakeFile(name, code)
60
+ cmd.setDiagnostics(TestDiagnostics.new(false))
61
+ cmd
62
+ end
63
+
64
+ def compile_or_raise cmd, args
65
+ if 0 != cmd.compile(args)
66
+ raise Mirah::MirahError, "Compilation failed"
67
+ end
68
+ rescue => e
69
+ raise e.cause if e.respond_to?(:cause) && e.cause
70
+ raise e
20
71
  end
21
72
 
22
73
  def compiler_name
23
74
  "new"
24
75
  end
76
+
77
+ def clean_tmp_files
78
+ return unless @tmp_classes
79
+ File.unlink(*@tmp_classes)
80
+ end
81
+
82
+ def dump_class_files class_map
83
+ class_map.each do |filename, bytes|
84
+ filename = "#{TEST_DEST}#{filename}.class"
85
+ FileUtils.mkdir_p(File.dirname(filename))
86
+ File.open(filename, 'wb') { |f| f.write(bytes) }
87
+ @tmp_classes << filename
88
+ end
89
+ end
90
+
91
+ def tmp_script_name
92
+ "script#{name.gsub(/\)|\(/,'_').capitalize}#{System.nano_time}"
93
+ end
94
+
95
+ def assert_raise_java(type, message=nil)
96
+ begin
97
+ yield
98
+ rescue Exception => e
99
+ ex = e
100
+ end
101
+ ex = ex.cause if ex.is_a? NativeException
102
+ assert_equal type, ex.class
103
+ if message
104
+ assert_equal message,
105
+ ex.message.to_s,
106
+ "expected error message to be '#{message}' but was '#{ex.message}'"
107
+ end
108
+ ex
109
+ end
110
+ end
111
+
112
+ class Test::Unit::TestCase
113
+ include JVMCompiler
114
+
115
+ def setup
116
+ @tmp_classes = Set.new
117
+ end
118
+
119
+ def cleanup
120
+ clean_tmp_files
121
+ end
25
122
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2010 The Mirah project authors. All Rights Reserved.
1
+ # Copyright (c) 2014 The Mirah project authors. All Rights Reserved.
2
2
  # All contributing project authors may be found in the NOTICE file.
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,30 +12,31 @@
12
12
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
+ require 'test_helper'
15
16
 
16
- class BiteScript::MethodBuilder
17
- def inot
18
- iconst_m1
19
- ixor
20
- end
17
+ class StaticFieldsTest < Test::Unit::TestCase
18
+ def test_static_field_inheritance_lookup_with_dot
19
+ cls, = with_finest_logging{compile(<<-EOF)}
20
+ import java.util.GregorianCalendar
21
+ puts GregorianCalendar.AM
22
+ EOF
21
23
 
22
- def lnot
23
- # TODO would any of these be faster?
24
- # iconst_m1; i2l
25
- # lconst_1; lneg
26
- ldc_long(-1)
27
- ixor
24
+ assert_output "0\n" do
25
+ cls.main(nil)
26
+ end
28
27
  end
29
28
 
30
- def op_to_bool
31
- done_label = label
32
- true_label = label
29
+ def test_static_field_inheritance_lookup_with_double_colon
30
+ return
31
+ pend("double colon is treated special for lookup") {
32
+ cls, = compile(<<-EOF)
33
+ import java.util.GregorianCalendar
34
+ puts GregorianCalendar::AM
35
+ EOF
33
36
 
34
- yield(true_label)
35
- iconst_0
36
- goto(done_label)
37
- true_label.set!
38
- iconst_1
39
- done_label.set!
37
+ assert_output "0\n" do
38
+ cls.main(nil)
39
+ end
40
+ }
40
41
  end
41
42
  end
@@ -14,11 +14,12 @@
14
14
  # limitations under the License.
15
15
 
16
16
  require 'test/unit'
17
- require 'mirah'
17
+ require 'java'
18
+ require 'dist/mirahc.jar'
18
19
 
19
20
  class BaseTypeTest < Test::Unit::TestCase
20
- java_import 'org.jruby.org.objectweb.asm.Type'
21
- java_import 'org.jruby.org.objectweb.asm.Opcodes'
21
+ java_import 'org.objectweb.asm.Type'
22
+ java_import 'org.objectweb.asm.Opcodes'
22
23
  java_import 'org.mirah.jvm.mirrors.BaseType'
23
24
  java_import 'org.mirah.jvm.mirrors.Member'
24
25
  java_import 'org.mirah.jvm.mirrors.MirrorTypeSystem'
@@ -14,38 +14,48 @@
14
14
  # limitations under the License.
15
15
 
16
16
  require 'test/unit'
17
- require 'mirah'
17
+ require 'java'
18
+ require 'dist/mirahc.jar'
18
19
 
19
20
  class BytecodeMirrorTest < Test::Unit::TestCase
20
- java_import 'org.jruby.org.objectweb.asm.Type'
21
- java_import 'org.mirah.jvm.mirrors.ClassPath'
21
+ java_import 'org.objectweb.asm.Type'
22
22
  java_import 'org.mirah.jvm.mirrors.MirrorTypeSystem'
23
+ java_import 'org.mirah.jvm.mirrors.ClassLoaderResourceLoader'
24
+ java_import 'org.mirah.jvm.mirrors.ClassResourceLoader'
23
25
  java_import 'org.mirah.jvm.types.JVMTypeUtils'
26
+ java_import 'org.mirah.IsolatedResourceLoader'
24
27
 
25
28
  def setup
26
- types = MirrorTypeSystem.new
27
- @loader = types.context.get(ClassPath).bytecode_loader
29
+ class_based_loader = ClassResourceLoader.new(MirrorTypeSystem.java_class)
30
+ loader = ClassLoaderResourceLoader.new(
31
+ IsolatedResourceLoader.new([TEST_DEST,FIXTURE_TEST_DEST].map{|u|java.net.URL.new "file:"+u}),
32
+ class_based_loader)
33
+ @types = MirrorTypeSystem.new nil, loader
28
34
  end
29
-
35
+
36
+ def load(desc)
37
+ @types.wrap(desc).resolve
38
+ end
39
+
30
40
  def test_parent
31
- mirror = @loader.loadMirror(Type.getType("I"))
41
+ mirror = load(Type.getType("I"))
32
42
  assert_equal("I", mirror.asm_type.descriptor)
33
43
  end
34
44
 
35
45
  def test_classloading
36
- mirror = @loader.loadMirror(Type.getType("Ljava/lang/Object;"))
46
+ mirror = load(Type.getType("Ljava/lang/Object;"))
37
47
  assert(!mirror.isError)
38
48
  assert_equal("java.lang.Object", mirror.name)
39
49
  end
40
50
 
41
51
  def test_inner_class
42
- mirror = @loader.loadMirror(Type.getType("Ljava/util/Map/Entry;"))
52
+ mirror = load(Type.getType("Ljava/util/Map/Entry;"))
43
53
  assert(!mirror.isError)
44
54
  assert_equal("java.util.Map$Entry", mirror.name)
45
55
  end
46
56
 
47
57
  def test_superclass
48
- mirror = @loader.loadMirror(Type.getType("Ljava/lang/String;"))
58
+ mirror = load(Type.getType("Ljava/lang/String;"))
49
59
  assert(!mirror.isError)
50
60
  assert_equal("java.lang.String", mirror.name)
51
61
 
@@ -56,13 +66,13 @@ class BytecodeMirrorTest < Test::Unit::TestCase
56
66
  end
57
67
 
58
68
  def test_interfaces
59
- mirror = @loader.loadMirror(Type.getType("Ljava/lang/String;"))
69
+ mirror = load(Type.getType("Ljava/lang/String;"))
60
70
  interfaces = mirror.interfaces.map {|t| t.resolve.name}
61
71
  assert_equal(['java.io.Serializable', 'java.lang.Comparable', 'java.lang.CharSequence'], interfaces)
62
72
  end
63
73
 
64
74
  def test_declared_field
65
- mirror = @loader.loadMirror(Type.getType("Ljava/lang/String;"))
75
+ mirror = load(Type.getType("Ljava/lang/String;"))
66
76
  field = mirror.getDeclaredField('hash')
67
77
  assert_equal(mirror, field.declaringClass)
68
78
  assert_equal('hash', field.name)
@@ -74,13 +84,23 @@ class BytecodeMirrorTest < Test::Unit::TestCase
74
84
  end
75
85
 
76
86
  def test_array
77
- mirror = @loader.loadMirror(Type.getType("[Ljava/lang/Object;"))
87
+ mirror = load(Type.getType("[Ljava/lang/Object;"))
78
88
  assert(JVMTypeUtils.isArray(mirror))
79
89
  assert_equal("Ljava/lang/Object;", mirror.getComponentType.asm_type.descriptor)
80
90
  end
81
91
 
82
- def test_retention
83
- mirror = @loader.loadMirror(Type.getType("Ljava/lang/annotation/Retention;"))
92
+ def test_annotation_retention_with_runtime
93
+ mirror = load(Type.getType("Ljava/lang/annotation/Retention;"))
84
94
  assert_equal("RUNTIME", mirror.retention)
85
95
  end
96
+
97
+ def test_annotation_retention_with_source
98
+ mirror = load(Type.getType("Ljava/lang/Override;"))
99
+ assert_equal("SOURCE", mirror.retention)
100
+ end
101
+
102
+ def test_annotation_retention_with_class
103
+ mirror = load(Type.getType("Lorg/foo/ImplicitClassRetAnno;"))
104
+ assert_equal("CLASS", mirror.retention)
105
+ end
86
106
  end