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