blob: 48bb86b62803167d6898d46b159e4e048b28daa8 [file] [log] [blame]
// Copyright (c) 2020, 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.
import '../native_testing.dart';
import 'null_assertions_test_lib.dart';
// Implementations of `NativeInterface` and `JSInterface` in a folder that is
// part of the allowlist for the `--native-null-assertions` flag. This file is
// treated as a web library, and therefore native members and `JS()` invocations
// should be checked.
@Native("AAA")
class AAA implements NativeInterface {
int get size native;
String get name native;
String? get optName native;
int method1() native;
String method2() native;
String? optMethod() native;
}
@Native('CCC')
class CCC implements JSInterface {
String get name => JS('String', '#.name', this);
String? get optName => JS('String|Null', '#.optName', this);
}
/// Returns an 'AAA' object that satisfies the interface.
AAA makeA() native;
/// Returns an 'AAA' object where each method breaks the interface's contract.
AAA makeAX() native;
/// Returns a 'CCC' object that satisfies the interface using `JS()`
/// invocations.
CCC makeC() native;
/// Returns a 'CCC' object where each method breaks the interface's contract.
CCC makeCX() native;
// The 'AAA' version of the code is passed only objects of a single native
// class, so the native method can be inlined (which happens in the optimizer).
// This tests that the null-check exists in the 'inlined' code.
@pragma('dart2js:noInline')
String describeAAA(AAA o) {
return '${o.name} ${o.method2()} ${o.size} ${o.method1()}';
}
@pragma('dart2js:noInline')
String describeOptAAA(AAA o) {
return '${o.optName} ${o.optMethod()}';
}
void testNativeNullAssertions(bool flagEnabled) {
nativeTesting();
setup();
AAA a = makeA();
BBB b = BBB();
Expect.equals(expectedA, describeNativeInterface(a));
Expect.equals(expectedB, describeNativeInterface(b));
Expect.equals(expectedA, describeAAA(a));
AAA x = makeAX(); // This object returns `null`!
// Since native members are in a web library, this should throw if null checks
// are enabled.
var checkExpectation = flagEnabled ? Expect.throws : (f) => f();
checkExpectation(() => describeNativeInterface(x));
checkExpectation(() => describeAAA(x));
checkExpectation(() => x.name);
checkExpectation(() => x.size);
checkExpectation(() => x.method1());
checkExpectation(() => x.method2());
// Now test that a nullable return type does not have a check.
Expect.equals(expectedOptA, describeOptNativeInterface(a));
Expect.equals(expectedOptB, describeOptNativeInterface(b));
Expect.equals(expectedOptX, describeOptNativeInterface(x));
Expect.equals(expectedOptA, describeOptAAA(a));
Expect.equals(expectedOptX, describeOptAAA(x));
}
void testJSInvocationNullAssertions(bool flagEnabled) {
nativeTesting();
setup();
CCC c = makeC();
CCC cx = makeCX();
Expect.equals(expectedC, describeJSInterface(c));
// Since invocations are in a web library, this should throw if null checks
// are enabled.
var checkExpectation = flagEnabled ? Expect.throws : (f) => f();
checkExpectation(() => describeJSInterface(cx));
// Test that invocations with a nullable static type do not have checks.
Expect.equals(expectedOptC, describeOptJSInterface(c));
Expect.equals(expectedOptCX, describeOptJSInterface(cx));
}