blob: ad274e5caf633bb881f3c3f7fa976932a005580f [file] [log] [blame]
// Copyright (c) 2014, 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.
// @dart = 2.7
// Unit test of the [NativeBehavior.processSpecString] method.
import 'package:expect/expect.dart';
import 'package:compiler/src/native/behavior.dart';
import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
import 'package:compiler/src/diagnostics/messages.dart';
import 'package:compiler/src/elements/types.dart';
import 'package:compiler/src/universe/side_effects.dart' show SideEffects;
import '../helpers/type_test_helper.dart';
const OBJECT = 'Object';
const NULL = 'Null';
class Listener extends DiagnosticReporter {
String errorMessage;
@override
internalError(spannable, message) {
errorMessage = message;
throw "error";
}
@override
reportError(message, [infos = const <DiagnosticMessage>[]]) {
errorMessage =
'${message.message.arguments}'; // E.g. "{text: Duplicate tag 'new'.}"
throw "error";
}
@override
DiagnosticMessage createMessage(spannable, messageKind,
[arguments = const {}]) {
return new DiagnosticMessage(null, spannable,
MessageTemplate.TEMPLATES[messageKind].message(arguments, null));
}
@override
noSuchMethod(_) => null;
}
void test(DartTypes dartTypes, String specString,
{List returns,
List creates,
SideEffects expectedSideEffects,
NativeThrowBehavior expectedThrows,
bool expectedNew,
bool expectedGvn,
bool expectError: false}) {
List actualReturns = [];
List actualCreates = [];
SideEffects actualSideEffects;
NativeThrowBehavior actualThrows;
bool actualNew;
bool actualGvn;
Listener listener = new Listener();
try {
NativeBehavior.processSpecString(dartTypes, listener, null, specString,
setSideEffects: (effects) => actualSideEffects = effects,
setThrows: (b) => actualThrows = b,
setIsAllocation: (b) => actualNew = b,
setUseGvn: (b) => actualGvn = b,
lookupType: (t, {required}) => t,
typesReturned: actualReturns,
typesInstantiated: actualCreates,
objectType: OBJECT,
nullType: NULL);
} catch (e) {
Expect.isTrue(expectError, 'Unexpected error "$specString"');
Expect.isNotNull(listener.errorMessage, 'Error message expected.');
return;
}
Expect.isFalse(expectError, 'Missing error for "$specString".');
Expect.isNull(listener.errorMessage, 'Unexpected error.');
if (returns != null) {
Expect.listEquals(returns, actualReturns, 'Unexpected returns.');
}
if (creates != null) {
Expect.listEquals(creates, actualCreates, 'Unexpected creates.');
}
Expect.equals(expectedSideEffects, actualSideEffects);
Expect.equals(expectedThrows, actualThrows);
Expect.equals(expectedNew, actualNew);
Expect.equals(expectedGvn, actualGvn);
}
void testWithSideEffects(DartTypes dartTypes, String specString,
{List returns, List creates, bool expectError: false}) {
void sideEffectsTest(String newSpecString, SideEffects expectedSideEffects,
{bool sideEffectsExpectError}) {
test(dartTypes, newSpecString,
returns: returns,
creates: creates,
expectedSideEffects: expectedSideEffects,
expectError: sideEffectsExpectError ?? expectError);
}
SideEffects emptySideEffects = new SideEffects.empty();
sideEffectsTest(specString + "effects:none;depends:none;", emptySideEffects);
sideEffectsTest(specString + "depends:none;effects:none;", emptySideEffects);
sideEffectsTest("effects:none;depends:none;" + specString, emptySideEffects);
sideEffectsTest("depends:none;effects:none;" + specString, emptySideEffects);
SideEffects effects = new SideEffects();
effects.clearChangesIndex();
effects.clearAllDependencies();
sideEffectsTest(specString + "effects:no-index;depends:none;", effects);
effects = new SideEffects();
effects.clearAllSideEffects();
effects.clearDependsOnIndexStore();
sideEffectsTest(specString + "effects:none;depends:no-index;", effects);
effects = new SideEffects();
effects.clearChangesInstanceProperty();
effects.clearChangesStaticProperty();
effects.clearAllDependencies();
sideEffectsTest(
specString + "effects:no-instance,no-static;depends:none;", effects);
effects = new SideEffects();
effects.clearAllSideEffects();
effects.clearDependsOnInstancePropertyStore();
effects.clearDependsOnStaticPropertyStore();
sideEffectsTest(
specString + "effects:none;depends:no-instance,no-static;", effects);
effects = new SideEffects();
effects.clearChangesInstanceProperty();
effects.clearChangesStaticProperty();
effects.clearDependsOnIndexStore();
sideEffectsTest(
specString + "effects:no-instance,no-static;depends:no-index;", effects);
effects = new SideEffects();
effects.clearChangesIndex();
effects.clearDependsOnInstancePropertyStore();
effects.clearDependsOnStaticPropertyStore();
sideEffectsTest(
specString + "effects:no-index;depends:no-instance,no-static;", effects);
effects = new SideEffects();
effects.clearChangesIndex();
sideEffectsTest(specString + "effects:no-index;depends:all;", effects);
effects = new SideEffects();
effects.clearDependsOnIndexStore();
sideEffectsTest(specString + "effects:all;depends:no-index;", effects);
effects = new SideEffects();
effects.clearChangesInstanceProperty();
effects.clearChangesStaticProperty();
sideEffectsTest(
specString + "effects:no-instance,no-static;depends:all;", effects);
effects = new SideEffects();
effects.clearDependsOnInstancePropertyStore();
effects.clearDependsOnStaticPropertyStore();
sideEffectsTest(
specString + "effects:all;depends:no-instance,no-static;", effects);
sideEffectsTest(specString + "effects:no-instance,no-static;", effects,
sideEffectsExpectError: true);
sideEffectsTest(specString + "depends:no-instance,no-static;", effects,
sideEffectsExpectError: true);
sideEffectsTest(specString + "effects:none;", effects,
sideEffectsExpectError: true);
sideEffectsTest(specString + "depends:all;", effects,
sideEffectsExpectError: true);
sideEffectsTest(
specString + "effects:no-instance,no-static;depends:foo;", effects,
sideEffectsExpectError: true);
sideEffectsTest(
specString + "effects:foo;depends:no-instance,no-static;", effects,
sideEffectsExpectError: true);
sideEffectsTest(specString + "effects:all;depends:foo", effects,
sideEffectsExpectError: true);
sideEffectsTest(specString + "effects:foo;depends:none;", effects,
sideEffectsExpectError: true);
sideEffectsTest(specString + "effects:;depends:none;", effects,
sideEffectsExpectError: true);
sideEffectsTest(specString + "effects:all;depends:;", effects,
sideEffectsExpectError: true);
}
void main() async {
var env = await TypeEnvironment.create('');
var types = env.types;
test(types, 'void', returns: [], creates: []);
test(types, '', returns: [OBJECT, NULL], creates: []);
test(types, 'var', returns: [OBJECT, NULL], creates: []);
test(types, 'A', returns: ['A'], creates: ['A']);
test(types, 'A|B', returns: ['A', 'B'], creates: ['A', 'B']);
test(types, 'A|B|C', returns: ['A', 'B', 'C'], creates: ['A', 'B', 'C']);
test(types, 'returns:void;', returns: [], creates: []);
test(types, 'returns:;', returns: [OBJECT, NULL], creates: []);
test(types, 'returns:var;', returns: [OBJECT, NULL], creates: []);
test(types, 'returns:A;', returns: ['A'], creates: ['A']);
test(types, 'returns:A|B;', returns: ['A', 'B'], creates: ['A', 'B']);
test(types, 'returns:A|B|C;',
returns: ['A', 'B', 'C'], creates: ['A', 'B', 'C']);
test(types, 'creates:void;', expectError: true);
test(types, 'creates:;', creates: []);
test(types, 'creates:var;', creates: []);
test(types, 'creates:A;', returns: [], creates: ['A']);
test(types, 'creates:A|B;', returns: [], creates: ['A', 'B']);
test(types, 'creates:A|B|C;', returns: [], creates: ['A', 'B', 'C']);
test(types, 'returns:void;creates:', returns: [], creates: []);
test(types, 'returns:;creates:', returns: [OBJECT, NULL], creates: []);
test(types, 'returns:var;creates:', returns: [OBJECT, NULL], creates: []);
test(types, 'returns:A;creates:', returns: ['A'], creates: []);
test(types, 'returns:A|B;creates:;', returns: ['A', 'B'], creates: []);
test(types, 'returns:A|B|C;creates:;', returns: ['A', 'B', 'C'], creates: []);
test(types, 'returns:void;creates:A;', returns: [], creates: ['A']);
test(types, 'returns:;creates:A|B;',
returns: [OBJECT, NULL], creates: ['A', 'B']);
test(types, 'returns:var;creates:A|B|C;',
returns: [OBJECT, NULL], creates: ['A', 'B', 'C']);
test(types, 'returns:A; creates:A|B|C; ',
returns: ['A'], creates: ['A', 'B', 'C']);
test(types, ' returns:A|B; creates:A|C;',
returns: ['A', 'B'], creates: ['A', 'C']);
test(types, ' returns:A|B|C; creates:A; ',
returns: ['A', 'B', 'C'], creates: ['A']);
testWithSideEffects(types, 'returns:void;', returns: [], creates: []);
testWithSideEffects(types, 'returns:void;', returns: [], creates: []);
testWithSideEffects(types, 'returns:;', returns: [OBJECT, NULL], creates: []);
testWithSideEffects(types, 'returns:var;',
returns: [OBJECT, NULL], creates: []);
testWithSideEffects(types, 'returns:A;', returns: ['A'], creates: ['A']);
testWithSideEffects(types, 'returns:A|B;',
returns: ['A', 'B'], creates: ['A', 'B']);
testWithSideEffects(types, 'returns:A|B|C;',
returns: ['A', 'B', 'C'], creates: ['A', 'B', 'C']);
testWithSideEffects(types, 'returns: A| B |C ;',
returns: ['A', 'B', 'C'], creates: ['A', 'B', 'C']);
testWithSideEffects(types, 'creates:void;', expectError: true);
testWithSideEffects(types, 'creates:;', creates: []);
testWithSideEffects(types, 'creates:var;', creates: []);
testWithSideEffects(types, 'creates:A;', returns: [], creates: ['A']);
testWithSideEffects(types, 'creates:A|B;', returns: [], creates: ['A', 'B']);
testWithSideEffects(types, 'creates:A|B|C;',
returns: [], creates: ['A', 'B', 'C']);
testWithSideEffects(types, 'returns:void;creates:;',
returns: [], creates: []);
testWithSideEffects(types, 'returns:;creates:;',
returns: [OBJECT, NULL], creates: []);
testWithSideEffects(types, 'returns:var;creates:;',
returns: [OBJECT, NULL], creates: []);
testWithSideEffects(types, 'returns:A;creates:;',
returns: ['A'], creates: []);
testWithSideEffects(types, 'returns:A|B;creates:;',
returns: ['A', 'B'], creates: []);
testWithSideEffects(types, 'returns:A|B|C;creates:;',
returns: ['A', 'B', 'C'], creates: []);
testWithSideEffects(types, 'returns:void;creates:A;',
returns: [], creates: ['A']);
testWithSideEffects(types, 'returns:;creates:A|B;',
returns: [OBJECT, NULL], creates: ['A', 'B']);
testWithSideEffects(types, 'returns:var;creates:A|B|C;',
returns: [OBJECT, NULL], creates: ['A', 'B', 'C']);
testWithSideEffects(types, 'returns:A; creates:A|B|C; ',
returns: ['A'], creates: ['A', 'B', 'C']);
testWithSideEffects(types, ' returns:A|B; creates:A|C;',
returns: ['A', 'B'], creates: ['A', 'C']);
testWithSideEffects(types, ' returns:A|B|C; creates:A; ',
returns: ['A', 'B', 'C'], creates: ['A']);
test(types, 'throws:may', expectedThrows: NativeThrowBehavior.MAY);
test(types, 'throws:never', expectedThrows: NativeThrowBehavior.NEVER);
test(types, 'throws:null(1)', expectedThrows: NativeThrowBehavior.NULL_NSM);
test(types, 'throws:null(1)+may',
expectedThrows: NativeThrowBehavior.NULL_NSM_THEN_MAY);
test(types, 'new:true', expectedNew: true);
test(types, 'new:false', expectedNew: false);
test(types, 'returns:A;new:true', returns: ['A'], expectedNew: true);
test(types, ' new : true ; returns:A;', returns: ['A'], expectedNew: true);
test(types, 'new:true;returns:A;new:true', expectError: true);
test(types, 'gvn:true', expectedGvn: true);
test(types, 'gvn:false', expectedGvn: false);
test(types, 'returns:A;gvn:true', returns: ['A'], expectedGvn: true);
test(types, ' gvn : true ; returns:A;', returns: ['A'], expectedGvn: true);
test(types, 'gvn:true;returns:A;gvn:true', expectError: true);
test(types, 'gvn: true; new: true', expectError: true);
test(types, 'gvn: true; new: false', expectedGvn: true, expectedNew: false);
test(types, 'gvn: false; new: true', expectedGvn: false, expectedNew: true);
test(types, 'gvn: false; new: false', expectedGvn: false, expectedNew: false);
}