Index: test/codegen/lib/mirrors/proxy_type_test.dart |
diff --git a/test/codegen/lib/mirrors/proxy_type_test.dart b/test/codegen/lib/mirrors/proxy_type_test.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c64c86236988b29baad56d0b3644b181af292448 |
--- /dev/null |
+++ b/test/codegen/lib/mirrors/proxy_type_test.dart |
@@ -0,0 +1,82 @@ |
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+library test.proxy_type; |
+ |
+import 'dart:mirrors'; |
+import 'package:expect/expect.dart'; |
+ |
+// This test is much longer that is strictly necessary to test |
+// InstanceMirror.type in the face of a reflectee overriding runtimeType, but |
+// shows a case where one might have legimate reason to override runtimeType. |
+// See section 2.2 in Mark Miller's Robust Composition: Towards a Unfied |
+// Approach to Access Control and Concurrency Control. |
+ |
+class Alice { |
+ Bob bob = new Bob(); |
+ Carol carol = new Carol(); |
+ sayFooUnattenuated() { |
+ bob.foo(carol); |
+ } |
+ sayFooAttenuated() { |
+ bool enabled = true; |
+ bool gate() => enabled; |
+ bob.foo(new CarolCaretaker(carol, gate)); |
+ enabled = false; // Attenuate a capability |
+ } |
+ sayBar() { |
+ bob.bar(); |
+ } |
+} |
+ |
+class Bob { |
+ Carol savedCarol; |
+ foo(Carol carol) { |
+ savedCarol = carol; // Store a capability |
+ carol.foo(); |
+ } |
+ bar() { |
+ savedCarol.foo(); |
+ } |
+} |
+ |
+class Carol { |
+ foo() => 'c'; |
+} |
+ |
+typedef bool Gate(); |
+ |
+class CarolCaretaker implements Carol { |
+ final Carol _carol; |
+ final Gate _gate; |
+ CarolCaretaker(this._carol, this._gate); |
+ |
+ foo() { |
+ if (!_gate()) throw new NoSuchMethodError(this, #foo, [], {}); |
+ return _carol.foo(); |
+ } |
+ |
+ Type get runtimeType => Carol; |
+} |
+ |
+main() { |
+ Alice alice1 = new Alice(); |
+ alice1.sayFooUnattenuated(); |
+ alice1.sayBar(); // Bob still has authority to use Carol |
+ |
+ Alice alice2 = new Alice(); |
+ alice2.sayFooAttenuated(); |
+ Expect.throws(() => alice2.sayBar(), |
+ (e) => e is NoSuchMethodError, |
+ 'Authority should have been attenuated'); |
+ |
+ // At the base level, a caretaker for a Carol masquerades as a Carol. |
+ CarolCaretaker caretaker = new CarolCaretaker(new Carol(), ()=>true); |
+ Expect.isTrue(caretaker is Carol); |
+ Expect.equals(Carol, caretaker.runtimeType); |
+ |
+ // At the reflective level, the caretaker is distinguishable. |
+ Expect.equals(reflectClass(CarolCaretaker), |
+ reflect(caretaker).type); |
+} |