Chromium Code Reviews| 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'; |
|
Siggi Cherem (dart-lang)
2016/12/29 22:46:57
missing `git add` for this file?
floitsch
2016/12/30 14:55:47
yes :(
done.
Siggi Cherem (dart-lang)
2017/01/03 23:23:54
I was still not able to find it :(
|
| + |
| +// 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(); |
| + } |
| +} |