| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library analyzer.test.utils; | 5 library analyzer.test.utils; |
| 6 | 6 |
| 7 import 'package:analyzer/src/generated/java_io.dart'; | 7 import 'package:analyzer/dart/ast/ast.dart'; |
| 8 import 'package:analyzer/dart/element/element.dart'; |
| 9 import 'package:analyzer/dart/element/type.dart'; |
| 10 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
| 8 import 'package:path/path.dart' as path; | 11 import 'package:path/path.dart' as path; |
| 9 import 'package:unittest/unittest.dart'; | 12 import 'package:unittest/unittest.dart'; |
| 10 | 13 |
| 11 void initializeTestEnvironment() { | 14 void initializeTestEnvironment([path.Context context]) { |
| 12 groupSep = ' | '; | 15 groupSep = ' | '; |
| 13 JavaFile.pathContext = path.posix; | |
| 14 } | 16 } |
| 17 |
| 18 /** |
| 19 * The type of an assertion which asserts properties of [T]s. |
| 20 */ |
| 21 typedef void Asserter<T>(T type); |
| 22 |
| 23 /** |
| 24 * The type of a function which given an [S], builds an assertion over [T]s. |
| 25 */ |
| 26 typedef Asserter<T> AsserterBuilder<S, T>(S arg); |
| 27 |
| 28 /** |
| 29 * The type of a function which given an [S0] and an S1, builds an assertion |
| 30 * over [T]s. |
| 31 */ |
| 32 typedef Asserter<T> AsserterBuilder2<S0, S1, T>(S0 arg0, S1 arg1); |
| 33 |
| 34 /** |
| 35 * The type of a function which given an [R] returns an [AsserterBuilder] over |
| 36 * [S]s and [T]s. That is, it returns a function which given an [S], returns |
| 37 * a function over [T]s. |
| 38 */ |
| 39 typedef AsserterBuilder<S, T> AsserterBuilderBuilder<R, S, T>(R arg); |
| 40 |
| 41 class AstFinder { |
| 42 /** |
| 43 * Return the declaration of the class with the given [className] in the given |
| 44 * compilation [unit]. |
| 45 */ |
| 46 static ClassDeclaration getClass(CompilationUnit unit, String className) { |
| 47 NodeList<CompilationUnitMember> unitMembers = unit.declarations; |
| 48 for (CompilationUnitMember unitMember in unitMembers) { |
| 49 if (unitMember is ClassDeclaration && unitMember.name.name == className) { |
| 50 return unitMember; |
| 51 } |
| 52 } |
| 53 fail('No class named $className in ${unit.element.source}'); |
| 54 return null; |
| 55 } |
| 56 |
| 57 /** |
| 58 * Return the declaration of the constructor with the given [constructorName]
in |
| 59 * the class with the given [className] in the given compilation [unit]. If |
| 60 * constructorName is null, return the default constructor; |
| 61 */ |
| 62 static ConstructorDeclaration getConstructorInClass( |
| 63 CompilationUnit unit, String className, String constructorName) { |
| 64 ClassDeclaration unitMember = getClass(unit, className); |
| 65 NodeList<ClassMember> classMembers = unitMember.members; |
| 66 for (ClassMember classMember in classMembers) { |
| 67 if (classMember is ConstructorDeclaration) { |
| 68 if (classMember.name?.name == constructorName) { |
| 69 return classMember; |
| 70 } |
| 71 } |
| 72 } |
| 73 fail('No constructor named $constructorName in $className'); |
| 74 return null; |
| 75 } |
| 76 |
| 77 /** |
| 78 * Return the declaration of the field with the given [fieldName] in the class |
| 79 * with the given [className] in the given compilation [unit]. |
| 80 */ |
| 81 static VariableDeclaration getFieldInClass( |
| 82 CompilationUnit unit, String className, String fieldName) { |
| 83 ClassDeclaration unitMember = getClass(unit, className); |
| 84 NodeList<ClassMember> classMembers = unitMember.members; |
| 85 for (ClassMember classMember in classMembers) { |
| 86 if (classMember is FieldDeclaration) { |
| 87 NodeList<VariableDeclaration> fields = classMember.fields.variables; |
| 88 for (VariableDeclaration field in fields) { |
| 89 if (field.name.name == fieldName) { |
| 90 return field; |
| 91 } |
| 92 } |
| 93 } |
| 94 } |
| 95 fail('No field named $fieldName in $className'); |
| 96 return null; |
| 97 } |
| 98 |
| 99 /** |
| 100 * Return the element of the field with the given [fieldName] in the class |
| 101 * with the given [className] in the given compilation [unit]. |
| 102 */ |
| 103 static FieldElement getFieldInClassElement( |
| 104 CompilationUnit unit, String className, String fieldName) { |
| 105 return getFieldInClass(unit, className, fieldName)?.name?.staticElement; |
| 106 } |
| 107 |
| 108 /** |
| 109 * Return the declaration of the method with the given [methodName] in the |
| 110 * class with the given [className] in the given compilation [unit]. |
| 111 */ |
| 112 static MethodDeclaration getMethodInClass( |
| 113 CompilationUnit unit, String className, String methodName) { |
| 114 ClassDeclaration unitMember = getClass(unit, className); |
| 115 NodeList<ClassMember> classMembers = unitMember.members; |
| 116 for (ClassMember classMember in classMembers) { |
| 117 if (classMember is MethodDeclaration) { |
| 118 if (classMember.name.name == methodName) { |
| 119 return classMember; |
| 120 } |
| 121 } |
| 122 } |
| 123 fail('No method named $methodName in $className'); |
| 124 return null; |
| 125 } |
| 126 |
| 127 /** |
| 128 * Return the statements in the body of a the method with the given |
| 129 * [methodName] in the class with the given [className] in the given |
| 130 * compilation [unit]. |
| 131 */ |
| 132 static List<Statement> getStatementsInMethod( |
| 133 CompilationUnit unit, String className, String methodName) { |
| 134 MethodDeclaration method = getMethodInClass(unit, className, methodName); |
| 135 BlockFunctionBody body = method.body; |
| 136 return body.block.statements; |
| 137 } |
| 138 |
| 139 /** |
| 140 * Return the statements in the body of the top-level function with the given |
| 141 * [functionName] in the given compilation [unit]. |
| 142 */ |
| 143 static List<Statement> getStatementsInTopLevelFunction( |
| 144 CompilationUnit unit, String functionName) { |
| 145 FunctionDeclaration function = getTopLevelFunction(unit, functionName); |
| 146 BlockFunctionBody body = function.functionExpression.body; |
| 147 return body.block.statements; |
| 148 } |
| 149 |
| 150 /** |
| 151 * Return the declaration of the top-level function with the given |
| 152 * [functionName] in the given compilation [unit]. |
| 153 */ |
| 154 static FunctionDeclaration getTopLevelFunction( |
| 155 CompilationUnit unit, String functionName) { |
| 156 NodeList<CompilationUnitMember> unitMembers = unit.declarations; |
| 157 for (CompilationUnitMember unitMember in unitMembers) { |
| 158 if (unitMember is FunctionDeclaration) { |
| 159 if (unitMember.name.name == functionName) { |
| 160 return unitMember; |
| 161 } |
| 162 } |
| 163 } |
| 164 fail('No toplevel function named $functionName found'); |
| 165 return null; |
| 166 } |
| 167 |
| 168 /** |
| 169 * Return the declaration of the top-level variable with the given |
| 170 * [variableName] in the given compilation [unit]. |
| 171 */ |
| 172 static VariableDeclaration getTopLevelVariable( |
| 173 CompilationUnit unit, String variableName) { |
| 174 NodeList<CompilationUnitMember> unitMembers = unit.declarations; |
| 175 for (CompilationUnitMember unitMember in unitMembers) { |
| 176 if (unitMember is TopLevelVariableDeclaration) { |
| 177 NodeList<VariableDeclaration> variables = |
| 178 unitMember.variables.variables; |
| 179 for (VariableDeclaration variable in variables) { |
| 180 if (variable.name.name == variableName) { |
| 181 return variable; |
| 182 } |
| 183 } |
| 184 } |
| 185 } |
| 186 fail('No toplevel variable named $variableName found'); |
| 187 return null; |
| 188 } |
| 189 |
| 190 /** |
| 191 * Return the top-level variable element with the given [name]. |
| 192 */ |
| 193 static TopLevelVariableElement getTopLevelVariableElement( |
| 194 CompilationUnit unit, String name) { |
| 195 return getTopLevelVariable(unit, name)?.name?.staticElement; |
| 196 } |
| 197 } |
| 198 |
| 199 /** |
| 200 * Class for compositionally building up assertions on types |
| 201 */ |
| 202 class TypeAssertions { |
| 203 // TODO(leafp): Make these matchers. |
| 204 // https://www.dartdocs.org/documentation/matcher/0.12.0%2B1/matcher/Matcher-c
lass.html |
| 205 |
| 206 /* Provides primitive types for basic type assertions */ |
| 207 final TypeProvider _typeProvider; |
| 208 |
| 209 TypeAssertions(this._typeProvider); |
| 210 |
| 211 /** |
| 212 * Primitive assertion for the dynamic type |
| 213 */ |
| 214 Asserter<DartType> get isDynamic => isType(_typeProvider.dynamicType); |
| 215 |
| 216 /** |
| 217 * Primitive assertion for the int type |
| 218 */ |
| 219 Asserter<DartType> get isInt => isType(_typeProvider.intType); |
| 220 |
| 221 /** |
| 222 * Primitive assertion for the list type |
| 223 */ |
| 224 Asserter<DartType> get isList => sameElement(_typeProvider.listType); |
| 225 |
| 226 /** |
| 227 * Primitive assertion for the map type |
| 228 */ |
| 229 Asserter<DartType> get isMap => sameElement(_typeProvider.mapType); |
| 230 |
| 231 /** |
| 232 * Primitive assertion for the num type |
| 233 */ |
| 234 Asserter<DartType> get isNum => isType(_typeProvider.numType); |
| 235 |
| 236 /** |
| 237 * Primitive assertion for the string type |
| 238 */ |
| 239 Asserter<DartType> get isString => isType(_typeProvider.stringType); |
| 240 |
| 241 /** |
| 242 * Given a type, produce an assertion that a type has the same element. |
| 243 */ |
| 244 Asserter<DartType> hasElement(Element element) => |
| 245 (DartType type) => expect(element, same(type.element)); |
| 246 |
| 247 /** |
| 248 * Given assertions for the argument and return types, produce an |
| 249 * assertion over unary function types. |
| 250 */ |
| 251 Asserter<DartType> isFunction2Of( |
| 252 Asserter<DartType> argType, Asserter<DartType> returnType) => |
| 253 (DartType type) { |
| 254 FunctionType fType = (type as FunctionType); |
| 255 argType(fType.normalParameterTypes[0]); |
| 256 returnType(fType.returnType); |
| 257 }; |
| 258 |
| 259 /** |
| 260 * Given an assertion for the base type and assertions over the type |
| 261 * parameters, produce an assertion over instantations. |
| 262 */ |
| 263 AsserterBuilder<List<Asserter<DartType>>, DartType> isInstantiationOf( |
| 264 Asserter<DartType> baseAssert) => |
| 265 (List<Asserter<DartType>> argAsserts) => (DartType type) { |
| 266 InterfaceType t = (type as InterfaceType); |
| 267 baseAssert(t); |
| 268 List<DartType> typeArguments = t.typeArguments; |
| 269 expect(typeArguments, hasLength(argAsserts.length)); |
| 270 for (int i = 0; i < typeArguments.length; i++) { |
| 271 argAsserts[i](typeArguments[i]); |
| 272 } |
| 273 }; |
| 274 |
| 275 /** |
| 276 * Assert that a type is the List type, and that the given assertion holds |
| 277 * over the type parameter. |
| 278 */ |
| 279 Asserter<InterfaceType> isListOf(Asserter<DartType> argAssert) => |
| 280 isInstantiationOf(isList)([argAssert]); |
| 281 |
| 282 /** |
| 283 * Assert that a type is the Map type, and that the given assertions hold |
| 284 * over the type parameters. |
| 285 */ |
| 286 Asserter<InterfaceType> isMapOf( |
| 287 Asserter<DartType> argAssert0, Asserter<DartType> argAssert1) => |
| 288 isInstantiationOf(isMap)([argAssert0, argAssert1]); |
| 289 |
| 290 /** |
| 291 * Assert that one type is the same as another |
| 292 */ |
| 293 Asserter<DartType> isType(DartType argument) => (DartType t) { |
| 294 expect(t, same(argument)); |
| 295 }; |
| 296 |
| 297 /** |
| 298 * Given a type, produce an assertion that a type has the same element. |
| 299 */ |
| 300 Asserter<DartType> sameElement(DartType elementType) => |
| 301 hasElement(elementType.element); |
| 302 } |
| OLD | NEW |