| Index: tests/language/generalized_function_type_test.dart
|
| diff --git a/tests/language/generalized_function_type_test.dart b/tests/language/generalized_function_type_test.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3c6d95099f3c9f0f0449ed1d04b6b7106cf96fab
|
| --- /dev/null
|
| +++ b/tests/language/generalized_function_type_test.dart
|
| @@ -0,0 +1,748 @@
|
| +// Copyright (c) 2016, 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 'generated_function_syntax_tests.dart';
|
| +
|
| +// By convention:
|
| +//
|
| +// T: generic type of typedef.
|
| +// A: generic type of returned function.
|
| +// B: generic type of function.
|
| +//
|
| +// Example:
|
| +// typedef F<T>: Function<A> Function<B>();
|
| +//
|
| +// We only use: Function, List, int (and function types).
|
| +// We import 'dart:core' directly and with prefix 'core'.
|
| +
|
| +abstract class Printable {
|
| + /// Builds a descriptive string that can be used as an identifier.
|
| + ///
|
| + /// The string is mainly used for disambiguation, and not for its readability.
|
| + void writeIdentifier(StringBuffer buffer);
|
| +}
|
| +
|
| +abstract class TypeLike implements Printable {
|
| + /// Prints `this` as valid Dart code for a Type.
|
| + void writeType(StringBuffer buffer);
|
| +
|
| + /// Whether this instance uses T in some way.
|
| + bool get usesT;
|
| +}
|
| +
|
| +/// Provides a unique integer for every parameter in a function.
|
| +int parameterNameCounter = 0;
|
| +
|
| +/// Whether `T` should be replaced with `int`.
|
| +bool shouldReplaceTWithInt = false;
|
| +
|
| +class Parameter implements Printable {
|
| + final TypeLike type;
|
| + final String name;
|
| +
|
| + Parameter(this.type, this.name);
|
| +
|
| + // Type or name can be null.
|
| + @override
|
| + writeIdentifier(buffer) {
|
| + if (type == null) {
|
| + buffer.write("null");
|
| + } else {
|
| + type.writeIdentifier(buffer);
|
| + }
|
| + buffer.write("_");
|
| + buffer.write(name);
|
| + }
|
| +
|
| + void writeType(StringBuffer buffer) {
|
| + assert(type != null || name != null);
|
| + if (name == null) {
|
| + type.writeType(buffer);
|
| + } else if (type == null) {
|
| + buffer.write(name);
|
| + } else {
|
| + type.writeType(buffer);
|
| + buffer.write(" ");
|
| + buffer.write(name);
|
| + }
|
| + }
|
| +
|
| + void writeInFunction(StringBuffer buffer) {
|
| + assert(type != null || name != null);
|
| + if (name == null) {
|
| + type.writeType(buffer);
|
| + buffer.write(" x");
|
| + buffer.write(parameterNameCounter++);
|
| + } else if (type == null) {
|
| + buffer.write(name);
|
| + } else {
|
| + type.writeType(buffer);
|
| + buffer.write(" ");
|
| + buffer.write(name);
|
| + }
|
| + }
|
| +
|
| + bool operator ==(other) {
|
| + return other is Parameter && name == other.name && type == other.type;
|
| + }
|
| +
|
| + int get hashCode {
|
| + return ((name.hashCode * 37) ^ type.hashCode) & 0xFFFFFFFF;
|
| + }
|
| +
|
| + bool get usesT => type?.usesT == true;
|
| +}
|
| +
|
| +class GenericParameter implements TypeLike {
|
| + final String name;
|
| + final TypeLike bound;
|
| +
|
| + GenericParameter(this.name, [this.bound]);
|
| +
|
| + // Bound may be null.
|
| + @override
|
| + writeIdentifier(buffer) {
|
| + buffer.write(name);
|
| + buffer.write("_");
|
| + if (bound == null) {
|
| + buffer.write("null");
|
| + } else {
|
| + bound.writeIdentifier(buffer);
|
| + }
|
| + }
|
| +
|
| + @override
|
| + writeType(buffer) {
|
| + buffer.write(name);
|
| + if (bound != null) {
|
| + buffer.write(" extends ");
|
| + bound.writeType(buffer);
|
| + }
|
| + }
|
| +
|
| + bool operator ==(other) {
|
| + return other is GenericParameter &&
|
| + name == other.name &&
|
| + bound == other.bound;
|
| + }
|
| +
|
| + int get hashCode {
|
| + return ((name.hashCode * 23) ^ bound.hashCode) & 0xFFFFFFFF;
|
| + }
|
| +
|
| + bool get usesT {
|
| + return bound?.usesT == true;
|
| + }
|
| +}
|
| +
|
| +void _describeList(StringBuffer buffer, List<Printable> list) {
|
| + if (list == null) {
|
| + buffer.write("0");
|
| + return;
|
| + }
|
| + buffer.write(list.length.toString());
|
| + buffer.write("_");
|
| + for (int i = 0; i < list.length; i++) {
|
| + if (i != 0) buffer.write("_");
|
| + list[i].writeIdentifier(buffer);
|
| + }
|
| +}
|
| +
|
| +void _writeTypes(StringBuffer buffer, List<TypeLike> list,
|
| + [String prefix = "", String postfix = ""]) {
|
| + if (list == null || list.isEmpty) return;
|
| + buffer.write(prefix);
|
| + for (int i = 0; i < list.length; i++) {
|
| + if (i != 0) buffer.write(", ");
|
| + list[i].writeType(buffer);
|
| + }
|
| + buffer.write(postfix);
|
| +}
|
| +
|
| +void _writeParameters(
|
| + StringBuffer buffer, List<Parameter> list, bool inFunction,
|
| + [String prefix = "", String postfix = ""]) {
|
| + if (list == null || list.isEmpty) return;
|
| + buffer.write(prefix);
|
| + for (int i = 0; i < list.length; i++) {
|
| + if (i != 0) buffer.write(", ");
|
| + if (inFunction) {
|
| + list[i].writeInFunction(buffer);
|
| + } else {
|
| + list[i].writeType(buffer);
|
| + }
|
| + }
|
| + buffer.write(postfix);
|
| +}
|
| +
|
| +bool _listUsesT(List elements) {
|
| + if (elements == null) return false;
|
| + return elements.any((p) => p.usesT);
|
| +}
|
| +
|
| +bool _listEquals(List list1, List list2) {
|
| + if (list1 == list2) return true; // Also covers both being null.
|
| + if (list1 == null || list2 == null) return false;
|
| + for (int i = 0; i < list1.length; i++) {
|
| + if (list1[i] != list2[i]) return false;
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +int _listHash(List list) {
|
| + if (list == null) return null.hashCode;
|
| + int result = 71;
|
| + for (int i = 0; i < list.length; i++) {
|
| + result = ((result * 11) ^ list[i].hashCode) & 0xFFFFFFFF;
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +class FunctionType implements TypeLike {
|
| + final TypeLike returnType;
|
| + final List<GenericParameter> generic;
|
| + final List<Parameter> required;
|
| + final List<Parameter> optional;
|
| + final List<Parameter> named;
|
| +
|
| + FunctionType(this.returnType, this.generic, this.required,
|
| + [this.optional, this.named]);
|
| +
|
| + @override
|
| + writeIdentifier(buffer) {
|
| + buffer.write("Fun_");
|
| + if (returnType == null) {
|
| + buffer.write("null");
|
| + } else {
|
| + returnType.writeIdentifier(buffer);
|
| + }
|
| + buffer.write("_");
|
| + _describeList(buffer, generic);
|
| + buffer.write("_");
|
| + _describeList(buffer, required);
|
| + buffer.write("_");
|
| + _describeList(buffer, optional);
|
| + buffer.write("_");
|
| + _describeList(buffer, named);
|
| + }
|
| +
|
| + @override
|
| + writeType(buffer) {
|
| + if (returnType != null) {
|
| + returnType.writeType(buffer);
|
| + buffer.write(" ");
|
| + }
|
| + buffer.write("Function");
|
| + if (generic != null) _writeTypes(buffer, generic, "<", ">");
|
| + buffer.write("(");
|
| + bool notInFunction = true;
|
| + _writeParameters(buffer, required, notInFunction);
|
| + if ((optional != null || named != null) &&
|
| + required != null &&
|
| + required.isNotEmpty) {
|
| + buffer.write(", ");
|
| + }
|
| + _writeParameters(buffer, optional, notInFunction, "[", "]");
|
| + _writeParameters(buffer, named, notInFunction, "{", "}");
|
| + buffer.write(")");
|
| + }
|
| +
|
| + /// Writes this type as if it was a function.
|
| + void writeFunction(StringBuffer buffer, String name, {bool replaceT = true}) {
|
| + shouldReplaceTWithInt = replaceT;
|
| + parameterNameCounter = 0;
|
| +
|
| + if (returnType != null) {
|
| + returnType.writeType(buffer);
|
| + buffer.write(" ");
|
| + }
|
| +
|
| + buffer.write(name);
|
| + if (generic != null) _writeTypes(buffer, generic, "<", ">");
|
| + buffer.write("(");
|
| + bool inFunction = true;
|
| + _writeParameters(buffer, required, inFunction);
|
| + if ((optional != null || named != null) &&
|
| + required != null &&
|
| + required.isNotEmpty) {
|
| + buffer.write(", ");
|
| + }
|
| + _writeParameters(buffer, optional, inFunction, "[", "]");
|
| + _writeParameters(buffer, named, inFunction, "{", "}");
|
| + buffer.write(") => null;");
|
| +
|
| + shouldReplaceTWithInt = false;
|
| + }
|
| +
|
| + bool operator ==(other) {
|
| + return returnType == other.returnType &&
|
| + _listEquals(generic, other.generic) &&
|
| + _listEquals(required, other.required) &&
|
| + _listEquals(optional, other.optional) &&
|
| + _listEquals(named, other.named);
|
| + }
|
| +
|
| + int get hashCode {
|
| + return ((returnType.hashCode * 13) ^
|
| + (_listHash(generic) * 17) ^
|
| + (_listHash(required) * 53) ^
|
| + (_listHash(optional) ^ 31) ^
|
| + (_listHash(named) * 87)) &
|
| + 0xFFFFFFFF;
|
| + }
|
| +
|
| + bool get usesT {
|
| + return returnType?.usesT == true ||
|
| + [generic, required, optional, named].any(_listUsesT);
|
| + }
|
| +}
|
| +
|
| +class NominalType implements TypeLike {
|
| + final String prefix;
|
| + final String name;
|
| + final List<TypeLike> generic;
|
| +
|
| + NominalType(this.name, [this.prefix, this.generic]);
|
| +
|
| + @override
|
| + writeIdentifier(buffer) {
|
| + buffer.write(prefix);
|
| + buffer.write("_");
|
| + buffer.write(name);
|
| + _describeList(buffer, generic);
|
| + }
|
| +
|
| + @override
|
| + writeType(buffer) {
|
| + if (prefix != null && prefix != "") {
|
| + buffer.write(prefix);
|
| + buffer.write(".");
|
| + }
|
| + if (shouldReplaceTWithInt && name == "T") {
|
| + buffer.write("int");
|
| + } else {
|
| + buffer.write(name);
|
| + }
|
| + _writeTypes(buffer, generic, "<", ">");
|
| + }
|
| +
|
| + bool operator ==(other) {
|
| + return other is NominalType && prefix == other.prefix && name == other.name;
|
| + }
|
| +
|
| + int get hashCode {
|
| + return ((prefix.hashCode * 37) ^ name.hashCode) & 0xFFFFFFFF;
|
| + }
|
| +
|
| + bool get usesT => name == "T" || _listUsesT(generic);
|
| +}
|
| +
|
| +List<FunctionType> buildFunctionTypes() {
|
| + List<GenericParameter> as = [
|
| + new GenericParameter("A"),
|
| + // new GenericParameter("A", new NominalType("int")),
|
| + // new GenericParameter("A", new NominalType("int", "core")),
|
| + ];
|
| + List<GenericParameter> bs = [
|
| + // new GenericParameter("B"),
|
| + // new GenericParameter("B", new NominalType("int")),
|
| + new GenericParameter("B", new NominalType("int", "core")),
|
| + ];
|
| + List<TypeLike> basicTypes = [
|
| + new NominalType("int"),
|
| + // new NominalType("int", "core"),
|
| + // new NominalType("List"),
|
| + // new NominalType("List", "core"),
|
| + new NominalType("Function"),
|
| + new NominalType("List", "", [new NominalType("Function")]),
|
| + new NominalType("List", "core", [new NominalType("int", "core")]),
|
| + new NominalType("List", "", [new NominalType("T")]),
|
| + // new NominalType("List", "", [new NominalType("Function")]),
|
| + ];
|
| +
|
| + List<TypeLike> basicsPlusNull = [
|
| + basicTypes,
|
| + [null]
|
| + ].expand((x) => x).toList();
|
| +
|
| + List<TypeLike> basicsPlusNullPlusB = [
|
| + basicsPlusNull,
|
| + [
|
| + new NominalType("B"),
|
| + new NominalType("List", "", [new NominalType("B")])
|
| + ]
|
| + ].expand((x) => x).toList();
|
| +
|
| + List<TypeLike> basicsPlusNullPlusA = [
|
| + basicsPlusNull,
|
| + [
|
| + new NominalType("A"),
|
| + new NominalType("List", "", [new NominalType("A")])
|
| + ]
|
| + ].expand((x) => x).toList();
|
| +
|
| + List<TypeLike> buildFunctionTypes(TypeLike returnType, TypeLike parameterType,
|
| + [List<GenericParameter> generics,
|
| + bool generateMoreCombinations = false]) {
|
| + List<TypeLike> result = [];
|
| +
|
| + if (parameterType == null) {
|
| + // int Function().
|
| + result.add(new FunctionType(returnType, generics, null));
|
| + } else if (parameterType == null && generateMoreCombinations) {
|
| + // int Function(int, {x})
|
| + result.add(new FunctionType(
|
| + returnType,
|
| + generics,
|
| + [new Parameter(new NominalType("int"), null)],
|
| + null,
|
| + [new Parameter(null, "x")]));
|
| + // int Function({x})
|
| + result.add(new FunctionType(
|
| + returnType, generics, null, null, [new Parameter(null, "x")]));
|
| + // int Function(int x, {x})
|
| + result.add(new FunctionType(
|
| + returnType,
|
| + generics,
|
| + [new Parameter(new NominalType("int"), "y")],
|
| + null,
|
| + [new Parameter(null, "x")]));
|
| + return result;
|
| + } else {
|
| + assert(parameterType != null);
|
| + // int Function(int x).
|
| + result.add(new FunctionType(
|
| + returnType, generics, [new Parameter(parameterType, "x")]));
|
| + if (generateMoreCombinations) {
|
| + // int Function([int x]).
|
| + result.add(new FunctionType(
|
| + returnType, generics, null, [new Parameter(parameterType, "x")]));
|
| + // int Function(int, [int x])
|
| + result.add(new FunctionType(
|
| + returnType,
|
| + generics,
|
| + [new Parameter(new NominalType("int"), null)],
|
| + [new Parameter(parameterType, "x")]));
|
| + // int Function(int x, [int x])
|
| + result.add(new FunctionType(
|
| + returnType,
|
| + generics,
|
| + [new Parameter(new NominalType("int"), "y")],
|
| + [new Parameter(parameterType, "x")]));
|
| + // int Function(int);
|
| + result.add(new FunctionType(
|
| + returnType, generics, [new Parameter(parameterType, null)]));
|
| + // int Function([int]);
|
| + result.add(new FunctionType(
|
| + returnType, generics, null, [new Parameter(parameterType, null)]));
|
| + // int Function(int, [int])
|
| + result.add(new FunctionType(
|
| + returnType,
|
| + generics,
|
| + [new Parameter(new NominalType("int"), null)],
|
| + [new Parameter(parameterType, null)]));
|
| + // int Function(int x, [int])
|
| + result.add(new FunctionType(
|
| + returnType,
|
| + generics,
|
| + [new Parameter(new NominalType("int"), "x")],
|
| + [new Parameter(parameterType, null)]));
|
| + }
|
| + }
|
| +
|
| + // Named arguments don't care for parameter types.
|
| + if (generateMoreCombinations) {
|
| + // int Function({int x}).
|
| + result.add(new FunctionType(returnType, generics, null, null,
|
| + [new Parameter(parameterType, "x")]));
|
| + // int Function(int, {int x})
|
| + result.add(new FunctionType(
|
| + returnType,
|
| + generics,
|
| + [new Parameter(new NominalType("int"), null)],
|
| + null,
|
| + [new Parameter(parameterType, "x")]));
|
| + // int Function(int x, {int x})
|
| + result.add(new FunctionType(
|
| + returnType,
|
| + generics,
|
| + [new Parameter(new NominalType("int"), "y")],
|
| + null,
|
| + [new Parameter(parameterType, "x")]));
|
| + }
|
| + return result;
|
| + }
|
| +
|
| + // The "smaller" function types. May also be used non-nested.
|
| + List<TypeLike> functionTypes = [];
|
| +
|
| + for (TypeLike returnType in basicsPlusNull) {
|
| + for (TypeLike parameterType in basicsPlusNull) {
|
| + bool generateMoreCombinations = true;
|
| + functionTypes.addAll(buildFunctionTypes(
|
| + returnType, parameterType, null, generateMoreCombinations));
|
| + }
|
| + }
|
| +
|
| + // These use `B` from the generic type of the enclosing function.
|
| + List<TypeLike> returnFunctionTypesB = [];
|
| + for (TypeLike returnType in basicsPlusNullPlusB) {
|
| + TypeLike parameterType = new NominalType("B");
|
| + returnFunctionTypesB.addAll(buildFunctionTypes(returnType, parameterType));
|
| + }
|
| + for (TypeLike parameterType in basicsPlusNull) {
|
| + TypeLike returnType = new NominalType("B");
|
| + returnFunctionTypesB.addAll(buildFunctionTypes(returnType, parameterType));
|
| + }
|
| +
|
| + for (TypeLike returnType in basicsPlusNullPlusA) {
|
| + for (TypeLike parameterType in basicsPlusNullPlusA) {
|
| + for (GenericParameter a in as) {
|
| + functionTypes
|
| + .addAll(buildFunctionTypes(returnType, parameterType, [a]));
|
| + }
|
| + }
|
| + }
|
| +
|
| + List<TypeLike> types = [];
|
| + types.addAll(functionTypes);
|
| +
|
| + // Now add some higher-order function types.
|
| + for (TypeLike returnType in functionTypes) {
|
| + types.addAll(buildFunctionTypes(returnType, null));
|
| + types.addAll(buildFunctionTypes(returnType, new NominalType("int")));
|
| + for (var b in bs) {
|
| + types.addAll(buildFunctionTypes(returnType, null, [b]));
|
| + types.addAll(buildFunctionTypes(returnType, new NominalType("int"), [b]));
|
| + }
|
| + }
|
| + for (TypeLike returnType in returnFunctionTypesB) {
|
| + for (var b in bs) {
|
| + types.addAll(buildFunctionTypes(returnType, null, [b]));
|
| + types.addAll(buildFunctionTypes(returnType, new NominalType("int"), [b]));
|
| + }
|
| + }
|
| +
|
| + return types;
|
| +}
|
| +
|
| +class Cls {
|
| + final String name;
|
| + final StringBuffer tests = new StringBuffer();
|
| + final StringBuffer fields = new StringBuffer();
|
| + final StringBuffer boolTests = new StringBuffer();
|
| + final StringBuffer statics = new StringBuffer();
|
| + final StringBuffer methods = new StringBuffer();
|
| +
|
| + Cls(this.name);
|
| +
|
| + void write(StringBuffer buffer) {
|
| + buffer.write("""
|
| +class $name<T> {
|
| + runTests({bool tIsDynamic}) {\n $tests }
|
| + boolTests() {\n$boolTests}
|
| + $fields
|
| + $methods
|
| +}
|
| + """);
|
| + }
|
| +}
|
| +
|
| +void generateTests({bool typedefsOnly}) {
|
| + StringBuffer typedefs = new StringBuffer();
|
| + StringBuffer typedefOnlyTests = new StringBuffer();
|
| + StringBuffer statics = new StringBuffer();
|
| +
|
| + // Keep methods and classes smaller by distributing over several different
|
| + // classes.
|
| + List<Cls> classes = [];
|
| + for (int i = 0; i < 100; i++) {
|
| + classes.add(new Cls("C$i"));
|
| + }
|
| +
|
| + var types = buildFunctionTypes();
|
| + print("""
|
| +// Copyright (c) 2016, 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.
|
| +
|
| +// GENERATED - DON'T EDIT.
|
| +// GENERATED - DON'T EDIT.
|
| +// GENERATED - DON'T EDIT.
|
| +// GENERATED - DON'T EDIT.
|
| +// GENERATED - DON'T EDIT.
|
| +// GENERATED - DON'T EDIT.
|
| +// GENERATED - DON'T EDIT.
|
| +// GENERATED - DON'T EDIT.
|
| +
|
| +import 'dart:core';
|
| +import 'dart:core' as core;
|
| +import 'package:expect/expect.dart';
|
| +
|
| +@NoInline()
|
| +@AssumeDynamic()
|
| +confuse(f) => f;
|
| +
|
| +final bool inCheckedMode =
|
| + (() { bool result = false; assert(result = true); return result; })();
|
| +
|
| +""");
|
| + int typeCounter = 0;
|
| + types.forEach((FunctionType t) {
|
| + Cls cls = classes[typeCounter % classes.length];
|
| + /*
|
| + StringBuffer identifierBuffer = new StringBuffer();
|
| + t.writeIdentifier(identifierBuffer);
|
| + String typeName = identifierBuffer.toString();
|
| + */
|
| + String typeName = "F$typeCounter";
|
| +
|
| + StringBuffer typeBuffer = new StringBuffer();
|
| + t.writeType(typeBuffer);
|
| + String typeCode = typeBuffer.toString();
|
| +
|
| + String staticFunName = "f$typeCounter";
|
| + StringBuffer staticFunBuffer = new StringBuffer();
|
| + t.writeFunction(staticFunBuffer, staticFunName);
|
| + String staticFunCode = staticFunBuffer.toString();
|
| +
|
| + String methodFunName = "m$typeCounter";
|
| + StringBuffer methodFunBuffer = new StringBuffer();
|
| + t.writeFunction(methodFunBuffer, methodFunName, replaceT: false);
|
| + String methodFunCode = methodFunBuffer.toString();
|
| +
|
| + String fieldName = "_$typeCounter";
|
| + cls.fields.writeln(" $typeCode $fieldName;");
|
| +
|
| + String localName = "l$typeCounter";
|
| +
|
| + typedefs.writeln("typedef $typeName<T> = $typeCode;");
|
| + statics.writeln(staticFunCode);
|
| + cls.methods.writeln(methodFunCode);
|
| +
|
| + // Just make sure that we reference all typedefs in typedefOnly mode.
|
| + typedefOnlyTests.writeln(" Expect.isFalse(true is $typeName);");
|
| +
|
| + cls.tests.writeln(" Expect.isTrue($staticFunName is $typeName);");
|
| + cls.tests.writeln(" Expect.isTrue(confuse($staticFunName) is $typeName);");
|
| + // In checked mode, verifies the type.
|
| + cls.tests.writeln(" $fieldName = $staticFunName as dynamic;");
|
| + cls.tests.writeln(" $typeCode $localName = $staticFunName as dynamic;");
|
| + cls.tests.writeln(" $fieldName = confuse($staticFunName);");
|
| + cls.tests.writeln(" $localName = confuse($staticFunName);");
|
| +
|
| + cls.tests.writeln(" Expect.isTrue($methodFunName is $typeName);");
|
| + cls.tests.writeln(" Expect.isTrue($methodFunName is $typeCode);");
|
| + cls.tests.writeln(" Expect.isTrue(confuse($methodFunName) is $typeName);");
|
| + // In checked mode, verifies the type.
|
| + cls.tests.writeln(" $fieldName = $methodFunName;");
|
| + cls.tests.writeln(" $localName = $methodFunName;");
|
| + cls.tests.writeln(" $fieldName = confuse($methodFunName);");
|
| + cls.tests.writeln(" $localName = confuse($methodFunName);");
|
| +
|
| + if (t.usesT) {
|
| + cls.tests.writeln(" Expect.isTrue($staticFunName is $typeName<int>);");
|
| + cls.tests.writeln(" Expect.isFalse($staticFunName is $typeName<bool>);");
|
| + cls.tests.writeln(
|
| + " Expect.isTrue(confuse($staticFunName) is $typeName<int>);");
|
| + cls.tests.writeln(
|
| + " Expect.isFalse(confuse($staticFunName) is $typeName<bool>);");
|
| + cls.tests.writeln(
|
| + " Expect.equals(tIsDynamic, $methodFunName is $typeName<bool>);");
|
| + cls.tests.writeln(" Expect.equals("
|
| + "tIsDynamic, confuse($methodFunName) is $typeName<bool>);");
|
| +
|
| +
|
| + cls.boolTests.writeln(" if (inCheckedMode) {");
|
| + cls.boolTests.writeln(
|
| + " Expect.throws(() { $fieldName = ($staticFunName as dynamic); });");
|
| + cls.boolTests.writeln(
|
| + " Expect.throws(() { $fieldName = confuse($staticFunName); });");
|
| + cls.boolTests.writeln(" Expect.throws("
|
| + "() { $localName = ($staticFunName as dynamic); });");
|
| + cls.boolTests.writeln(" Expect.throws("
|
| + "() { $localName = confuse($staticFunName); });");
|
| + cls.boolTests.writeln(" }");
|
| + cls.boolTests.writeln("$typeCode $localName = $methodFunName;");
|
| +
|
| + // In checked mode, verifies the type.
|
| + cls.boolTests.writeln(" $fieldName = $methodFunName;");
|
| + cls.boolTests.writeln(" $fieldName = confuse($methodFunName);");
|
| + }
|
| +
|
| + typeCounter++;
|
| + });
|
| +
|
| + if (typedefsOnly) {
|
| + print("""
|
| +$typedefs
|
| +void runTests() {
|
| +$typedefOnlyTests
|
| +}
|
| +""");
|
| + return;
|
| + }
|
| +
|
| + for (var cls in classes) {
|
| + var buffer = new StringBuffer();
|
| + cls.write(buffer);
|
| + print(buffer.toString());
|
| + }
|
| + print("""
|
| +$typedefs
|
| +$statics
|
| +
|
| +void runTests() {
|
| +""");
|
| + for (var cls in classes) {
|
| + print("""
|
| + new ${cls.name}().runTests(tIsDynamic: true);
|
| + new ${cls.name}<int>().runTests(tIsDynamic: false);
|
| + new ${cls.name}<bool>().boolTests();
|
| +""");
|
| + }
|
| + print("} // main");
|
| +}
|
| +
|
| +void printUsage() {
|
| + print("""
|
| +This program can be run in two modes:
|
| +1. Generating generalized function-type tests.
|
| +2. Running the tests imported from "generated_function_syntax_tests.dart".
|
| +
|
| +It is assumed that the "generated_function_syntax_tests.dart" file is the output
|
| +of a run of this program.
|
| +
|
| +To generate the tests run with either
|
| +* `--generate-typedefs`, or
|
| +* `--generate-all`.
|
| +
|
| +The first generates only tests that use function-type syntax in typedefs.
|
| +The latter generates tests for the same syntax in other locations.
|
| +
|
| +Normally the tests don't need to be regenerated.
|
| +If necessary, a typical workflow would look like follows:
|
| +
|
| +dart generalized_function_type_test.dart --generate-all > generated_function_syntax_tests.dart
|
| +""");
|
| +}
|
| +
|
| +void main(List<String> arguments) {
|
| + if (arguments.length > 0) {
|
| + if (arguments.length != 1) {
|
| + printUsage();
|
| + return;
|
| + }
|
| + if (arguments[0] == "--generate-typedefs") {
|
| + generateTests(typedefsOnly: true);
|
| + } else if (arguments[0] == "--generate-all") {
|
| + generateTests(typedefsOnly: false);
|
| + } else {
|
| + printUsage();
|
| + return;
|
| + }
|
| + } else {
|
| + runTests();
|
| + }
|
| +}
|
|
|