Second batch of private name tests.

Additional tests for private classes exported via a public typedef.

Change-Id: I443b1e32efa6140f319e9acc8c498bb9f5e3d27d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/193828
Reviewed-by: Nate Bosch <nbosch@google.com>
Commit-Queue: Leaf Petersen <leafp@google.com>
This commit is contained in:
Leaf Petersen 2021-04-07 01:09:09 +00:00 committed by commit-bot@chromium.org
parent d8da40ec52
commit 0fa7878d56
11 changed files with 488 additions and 28 deletions

View file

@ -0,0 +1,44 @@
// Copyright (c) 2021, 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.
// SharedOptions=--enable-experiment=nonfunction-type-aliases
// Test that private names exported via public typedefs can be used for casts
import "package:expect/expect.dart";
import "private_name_library.dart";
class Derived1 extends PublicClass {}
class Derived2 implements PublicClass {
noSuchMethod(_) {}
}
void test1() {
// Test casts from a derived subclass.
var d1 = Derived1();
Expect.equals(d1, d1 as Derived1);
Expect.equals(d1, d1 as PublicClass);
Expect.equals(d1, d1 as AlsoPublicClass);
Expect.throws(() => d1 as Derived2);
// Test casts from a derived implementation
var d2 = Derived2();
Expect.throws(() => d2 as Derived1);
Expect.equals(d2, d2 as PublicClass);
Expect.equals(d2, d2 as AlsoPublicClass);
Expect.equals(d2, d2 as Derived2);
// Test casts from the exported private subclass.
var p = PublicClass();
Expect.throws(() => p as Derived1);
Expect.equals(p, p as PublicClass);
Expect.equals(p, p as AlsoPublicClass);
Expect.throws(() => p as Derived2);
}
void main() {
test1();
}

View file

@ -0,0 +1,43 @@
// Copyright (c) 2021, 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.
// SharedOptions=--enable-experiment=nonfunction-type-aliases
// Test that private names exported via public typedefs allow creation.
import "package:expect/expect.dart";
import "private_name_library.dart";
void test1() {
// Test that a private class can be created via an exported public name using
// an unnamed constructor.
var p = PublicClass();
Expect.equals(privateLibrarySentinel, p.x);
Expect.equals(privateLibrarySentinel, p.instanceMethod());
Expect.equals(privateLibrarySentinel, callPrivateInstanceMethod(p));
}
void test2() {
// Test that a private class can be created via an exported public name using
// a named constructor.
var p = AlsoPublicClass.named(1);
Expect.equals(1, p.x);
Expect.equals(privateLibrarySentinel, p.instanceMethod());
Expect.equals(privateLibrarySentinel, callPrivateInstanceMethod(p));
}
void test3() {
// Test that a private class can be created as const via an exported public
// name.
const c1 = PublicClass();
const c2 = AlsoPublicClass();
Expect.identical(c1, c2);
}
void main() {
test1();
test2();
test3();
}

View file

@ -0,0 +1,66 @@
// Copyright (c) 2021, 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.
// SharedOptions=--enable-experiment=nonfunction-type-aliases
// Test that private names exported via public typedefs may not appear multiple
// times in a super-interface graph.
import "private_name_library.dart";
/// Test that having a private class in the implements and extends class via two
/// different public names is an error.
class A0 extends PublicClass implements AlsoPublicClass {
// ^
// [cfe] '_PrivateClass' can't be used in both 'extends' and 'implements' clauses.
// ^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.IMPLEMENTS_SUPER_CLASS
}
/// Test that having a private class in the implements class twice via the same
/// public name is an error.
class A1 implements PublicClass, PublicClass {
// ^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.IMPLEMENTS_REPEATED
// [cfe] unspecified
noSuchMethod(_) => null;
}
/// Test that having a private class in the implements class twice via two
/// different public names is an error.
class A2 implements PublicClass, AlsoPublicClass {
// ^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.IMPLEMENTS_REPEATED
// [cfe] unspecified
noSuchMethod(_) => null;
}
/// Helper class for the following test
class A3 extends PublicGenericClassOfInt {}
/// Test that having a private generic class in the super-interface graph
/// twice with two different generic instantiations is an error.
class A4 extends A3 implements PublicGenericClass<String> {
// [error line 42, column 1, length 411]
// [analyzer] COMPILE_TIME_ERROR.CONFLICTING_GENERIC_INTERFACES
// ^
// [cfe] 'A4' can't implement both '_PrivateGenericClass<int>' and '_PrivateGenericClass<String>'
}
/// Test that having a private generic class in the super-interface graph
/// twice at the same instantiation is not an error.
class A5 extends A3 implements PublicGenericClass<int> {}
/// Test that having a private generic class in the implements clause twice with
/// two different generic instantiations is an error.
class A6 implements PublicGenericClass<int>, PublicGenericClass<String> {
// [error line 55, column 1, length 546]
// [analyzer] COMPILE_TIME_ERROR.CONFLICTING_GENERIC_INTERFACES
// ^
// [cfe] 'A6' can't implement both '_PrivateGenericClass<int>' and '_PrivateGenericClass<String>'
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.IMPLEMENTS_REPEATED
}
void main() {}

View file

@ -10,36 +10,83 @@ import "package:expect/expect.dart";
import "private_name_library.dart";
/// Extend a private class via a public typedef without overriding any methods.
class Derived extends PublicClass {
Derived() : super(0);
// Check that super constructor calls work.
Derived() : super();
}
/// Extend a private class via a public typedef overriding methods and
/// properties. The final field `x` is overriden with a getter which returns
/// different values every time it is called.
class AlsoDerived extends AlsoPublicClass {
AlsoDerived() : super.named(0);
int instanceMethod() => 0;
int _privateInstanceMethod() => 0;
int backingStore = publicLibrarySentinel;
int get x => backingStore++;
int get y => super.x;
// Check that named super constructors work. Use the private sentinel value
// to allow us to distinguish reads of `x` from `super.x`.
AlsoDerived() : super.named(privateLibrarySentinel);
// Override the instanceMethod to return a distinguishing value.
int instanceMethod() => publicLibrarySentinel;
// Add a non-overriding private method with the same textual name as a private
// name in the super class which returns a distinguishing value.
int _privateInstanceMethod() => publicLibrarySentinel;
}
/// Test that inherited methods work correctly.
void test1() {
{
PublicClass p = Derived();
Expect.equals(3, p.instanceMethod());
Expect.throwsNoSuchMethodError(() => (p as dynamic)._privateInstanceMethod());
}
PublicClass p = Derived();
Expect.equals(privateLibrarySentinel, p.instanceMethod());
// Calling the inherited private method from the private library should work.
Expect.equals(privateLibrarySentinel, callPrivateInstanceMethod(p));
Expect.equals(privateLibrarySentinel, callInstanceMethod(p));
// Calling the inherited private method from this library should throw.
Expect.throwsNoSuchMethodError(() => (p as dynamic)._privateInstanceMethod());
}
/// Test that inherited methods work correctly.
/// Test that overriden methods work correctly.
void test2() {
{
var p = AlsoDerived();
Expect.equals(0, p.instanceMethod());
Expect.equals(0, p._privateInstanceMethod());
Expect.equals(0, (p as dynamic)._privateInstanceMethod());
}
var p = AlsoDerived();
Expect.equals(publicLibrarySentinel, p.instanceMethod());
// Calling the overriden private method from this library should work.
Expect.equals(publicLibrarySentinel, p._privateInstanceMethod());
// Calling the inherited private method from the private library should work.
Expect.equals(privateLibrarySentinel, callPrivateInstanceMethod(p));
// Calling the overriden private method dynamically from this library should
// work.
Expect.equals(publicLibrarySentinel, (p as dynamic)._privateInstanceMethod());
}
/// Test that inherited properties work correctly
void test3() {
var p = Derived();
// Reading the virtual field should give the private value
Expect.equals(privateLibrarySentinel, p.x);
// Reading the virtual field from the private library should give the private
// value
Expect.equals(privateLibrarySentinel, readInstanceField(p));
}
/// Test that overriden properties work correctly.
void test4() {
var p = AlsoDerived();
// Reading the original virtual field should give the private value.
Expect.equals(privateLibrarySentinel, p.y);
// Reading the overriding getter from this library should give the public
// value and increment it each time it is called.
Expect.equals(publicLibrarySentinel, readInstanceField(p));
// Reading the overriding getter from the original library should give the
// public value and increment it each time it is called.
Expect.equals(publicLibrarySentinel + 1, p.x);
Expect.equals(privateLibrarySentinel, p.y);
Expect.equals(publicLibrarySentinel + 2, readInstanceField(p));
Expect.equals(publicLibrarySentinel + 3, p.x);
}
void main() {
test1();
test2();
test3();
test4();
}

View file

@ -0,0 +1,32 @@
// Copyright (c) 2021, 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.
// SharedOptions=--enable-experiment=nonfunction-type-aliases
// Test that private names exported via public typedefs allow implementation
import "package:expect/expect.dart";
import "private_name_library.dart";
class Derived implements PublicClass {
int x;
Derived(this.x);
int instanceMethod() => publicLibrarySentinel;
int _privateInstanceMethod() => publicLibrarySentinel;
}
void test1() {
PublicClass _ = Derived(publicLibrarySentinel);
var p = Derived(publicLibrarySentinel);
Expect.equals(publicLibrarySentinel, p.instanceMethod());
// Calling the private instance method from this library should succeed.
Expect.equals(publicLibrarySentinel, p._privateInstanceMethod());
// Calling the private instance method from the other library should fail.
Expect.throwsNoSuchMethodError(() => callPrivateInstanceMethod(p));
}
void main() {
test1();
}

View file

@ -0,0 +1,43 @@
// Copyright (c) 2021, 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.
// SharedOptions=--enable-experiment=nonfunction-type-aliases
// Test that private names exported via public typedefs can be used for instance
// checks
import "package:expect/expect.dart";
import "private_name_library.dart";
class Derived1 extends PublicClass {}
class Derived2 implements PublicClass {
// Dummy implementation for the class using noSuchMethod.
noSuchMethod(_) {}
}
void test1() {
var d1 = Derived1();
Expect.isTrue(d1 is Derived1);
Expect.isTrue(d1 is PublicClass);
Expect.isTrue(d1 is AlsoPublicClass);
Expect.isFalse(d1 is Derived2);
var d2 = Derived2();
Expect.isFalse(d2 is Derived1);
Expect.isTrue(d2 is PublicClass);
Expect.isTrue(d2 is AlsoPublicClass);
Expect.isTrue(d2 is Derived2);
var p = PublicClass();
Expect.isFalse(p is Derived1);
Expect.isTrue(p is PublicClass);
Expect.isTrue(p is AlsoPublicClass);
Expect.isFalse(p is Derived2);
}
void main() {
test1();
}

View file

@ -7,26 +7,74 @@
library private;
// Sentinel values for checking that the correct methods are called. Methods
// defined in this library return the private sentinel, and (potentially
// overriding) methods defined in other libraries return the public sentinel.
// By checking the return value of methods against the respective sentinels,
// test expectations can establish whether the correct method has been called.
const int privateLibrarySentinel = -1;
const int publicLibrarySentinel = privateLibrarySentinel + 1;
// A private class that will be exported via a public typedef.
class _PrivateClass {
int x;
_PrivateClass(this.x);
final int x;
const _PrivateClass() : x = privateLibrarySentinel;
_PrivateClass.named(this.x);
static int staticMethod() => 3;
static int _privateStaticMethod() => 3;
int instanceMethod() => 3;
int _privateInstanceMethod() => 3;
static int staticMethod() => privateLibrarySentinel;
static int _privateStaticMethod() => privateLibrarySentinel;
int instanceMethod() => privateLibrarySentinel;
int _privateInstanceMethod() => privateLibrarySentinel;
}
// Export the private class publicly, along with a factory.
typedef PublicClass = _PrivateClass;
PublicClass mkPublicClass() => PublicClass(0);
PublicClass mkPublicClass() => PublicClass();
// Export the private class publicly via an indirection through another private
// typedef, along with a factory.
typedef _PrivateTypeDef = _PrivateClass;
typedef AlsoPublicClass = _PrivateTypeDef;
AlsoPublicClass mkAlsoPublicClass() => AlsoPublicClass(0);
AlsoPublicClass mkAlsoPublicClass() => AlsoPublicClass();
// A private generic class which will be exported through a public typedef.
class _PrivateGenericClass<T> {
static int staticMethod() => 3;
static int staticMethod() => privateLibrarySentinel;
}
// Export the private generic class publicly, along with a factory and a
// specific instantiation.
typedef PublicGenericClass<T> = _PrivateGenericClass<T>;
PublicGenericClass<T> mkPublicGenericClass<T>() => PublicGenericClass();
typedef PublicGenericClassOfInt = _PrivateGenericClass<int>;
// Helper methods to do virtual calls on instances of _PrivateClass in this
// library context.
int callPrivateInstanceMethod(_PrivateClass other) => other._privateInstanceMethod();
int callInstanceMethod(_PrivateClass other) => other.instanceMethod();
int readInstanceField(_PrivateClass other) => other.x;
// A private mixin to be exported via a typedef.
mixin _PrivateMixin {
int mixinMethod() => privateLibrarySentinel;
int _privateMixinMethod() => privateLibrarySentinel;
}
// Helper method to call a private method on the mixin in this library context.
int callPrivateMixinMethod(_PrivateMixin other) => other._privateMixinMethod();
// Export the private mixin
typedef PublicMixin = _PrivateMixin;
// A private super-mixin which is intended to be mixed onto PublicClass
// and which makes super calls into it.
mixin _PrivateSuperMixin on PublicClass {
int mixinMethod() => super.instanceMethod();
int _privateMixinMethod() => super._privateInstanceMethod();
}
// Call the private SuperMixinMethod
int callPrivateSuperMixinMethod(_PrivateSuperMixin other) =>
other._privateMixinMethod();
// Export the private super-mixin.
typedef PublicSuperMixin = _PrivateSuperMixin;

View file

@ -0,0 +1,19 @@
// Copyright (c) 2021, 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.
// SharedOptions=--enable-experiment=nonfunction-type-aliases
// Test that a private mixin exported via a typedef cannot be used as a class.
import "private_name_library.dart";
/// Class that attempts to use a private mixin as a class via a public typedef
/// name.
class A0 extends PublicMixin {}
// ^
// [cfe] The superclass, '_PrivateMixin', has no unnamed constructor that takes no arguments.
// ^^^^^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.EXTENDS_NON_CLASS
void main() {}

View file

@ -0,0 +1,75 @@
// Copyright (c) 2021, 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.
// SharedOptions=--enable-experiment=nonfunction-type-aliases
// Test that private names exported via public typedefs can be used as mixins.
import "package:expect/expect.dart";
import "private_name_library.dart";
// Class that mixes in a private mixin via a public name.
class Derived0 with PublicMixin {}
void test0() {
// Test that the Derived0 class receives the PublicMixin methods.
PublicMixin p = Derived0();
Expect.equals(privateLibrarySentinel, p.mixinMethod());
// The private mixin method is accessible in the original library.
Expect.equals(privateLibrarySentinel, callPrivateMixinMethod(p));
// The private mixin method is not accessible in this library.
Expect.throwsNoSuchMethodError(() => (p as dynamic)._privateMixinMethod());
}
// Class that mixes in a private mixin via a public name and overrides the
// PublicMixin methods.
class Derived1 with PublicMixin {
int mixinMethod() => publicLibrarySentinel;
int _privateMixinMethod() => publicLibrarySentinel;
}
void test1() {
// Test that the mixed in methods have been overriden correctly, and that the
// private methods from the two libraries resolve correctly.
var p = Derived1();
Expect.equals(publicLibrarySentinel, p.mixinMethod());
// The overriding private mixin method is accessible in this library.
Expect.equals(publicLibrarySentinel, p._privateMixinMethod());
// The original private mixin method is accessible in the other library.
Expect.equals(privateLibrarySentinel, callPrivateMixinMethod(p));
}
class _Derived2 extends PublicClass {}
// This class mixes a private super-mixin onto a subclass of a private class,
// and also defines new library private members with the same textual name as
// private members defined in the other library.
class Derived2 extends _Derived2 with PublicSuperMixin {
int _privateMixinMethod() => publicLibrarySentinel;
int _privateInstanceMethod() => publicLibrarySentinel;
}
void test2() {
// Test that the super-mixin methods resolve correctly.
var p = Derived2();
PublicSuperMixin _ = p; // Check assignability
PublicClass __ = p; // Check assignability
// The mixin and instance methods are accessible.
Expect.equals(privateLibrarySentinel, p.mixinMethod());
Expect.equals(privateLibrarySentinel, p.instanceMethod());
// The original private mixin and instance methods are accessible in the
// original library.
Expect.equals(privateLibrarySentinel, callPrivateSuperMixinMethod(p));
Expect.equals(privateLibrarySentinel, callPrivateInstanceMethod(p));
// The new private mixin and instance methods are acessible in this library.
Expect.equals(publicLibrarySentinel, p._privateMixinMethod());
Expect.equals(publicLibrarySentinel, p._privateInstanceMethod());
}
void main() {
test0();
test1();
test2();
}

View file

@ -15,13 +15,14 @@ import "private_name_library.dart";
/// Test that each public typedef can be used to access static methods.
void test1() {
{
Expect.equals(3, PublicClass.staticMethod());
Expect.equals(privateLibrarySentinel, PublicClass.staticMethod());
PublicClass.staticMethod().expectStaticType<Exactly<int>>();
Expect.equals(3, AlsoPublicClass.staticMethod());
Expect.equals(privateLibrarySentinel, AlsoPublicClass.staticMethod());
AlsoPublicClass.staticMethod().expectStaticType<Exactly<int>>();
Expect.equals(3, PublicGenericClassOfInt.staticMethod());
Expect.equals(
privateLibrarySentinel, PublicGenericClassOfInt.staticMethod());
PublicGenericClassOfInt.staticMethod().expectStaticType<Exactly<int>>();
}
}

View file

@ -0,0 +1,42 @@
// Copyright (c) 2021, 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.
// SharedOptions=--enable-experiment=nonfunction-type-aliases
// Test that private names exported via public typedefs can be used in a try
// catch.
import "package:expect/expect.dart";
import "private_name_library.dart";
class Derived extends PublicClass {}
void test1() {
try {
throw Derived();
} on PublicClass catch (e) {}
try {
throw Derived();
} on Derived catch (e) {}
try {
throw PublicClass();
} on PublicClass catch (e) {}
try {
throw PublicClass();
} on AlsoPublicClass catch (e) {}
Expect.throws(() {
try {
throw PublicClass();
} on Derived catch (e) {}
});
}
void main() {
test1();
}