Skip to content

Commit a264749

Browse files
committed
test(symbols): Track the symbols we export from the angular library
Closes dart-archive#398
1 parent 1571459 commit a264749

File tree

1 file changed

+278
-0
lines changed

1 file changed

+278
-0
lines changed

test/angular_spec.dart

Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ library angular_spec;
22

33
import '_specs.dart';
44
import 'package:angular/utils.dart';
5+
import 'dart:mirrors';
6+
//import 'package:angular/angular.dart' as angular;
57

68
main() {
79
describe('angular.dart unittests', () {
@@ -40,4 +42,280 @@ main() {
4042
}).toThrow('Unknown function type, expecting 0 to 5 args.');
4143
});
4244
});
45+
46+
47+
48+
_getSymbolsFromLibrary(String libraryName) {
49+
var names = [];
50+
var SYMBOL_NAME = new RegExp('"(.*)"');
51+
_unwrapSymbol(sym) => SYMBOL_NAME.firstMatch(sym.toString()).group(1);
52+
53+
var seen = {};
54+
55+
56+
57+
extractSymbols(LibraryMirror lib) {
58+
lib.declarations.forEach((symbol, _) {
59+
names.add([_unwrapSymbol(symbol), _unwrapSymbol(lib.qualifiedName)]);
60+
});
61+
62+
lib.libraryDependencies.forEach((LibraryDependencyMirror libDep) {
63+
LibraryMirror target = libDep.targetLibrary;
64+
if (!libDep.isExport) return;
65+
if (!seen.containsKey(target)) {
66+
seen[target] = true;
67+
extractSymbols(target);
68+
}
69+
});
70+
};
71+
72+
var lib = currentMirrorSystem().findLibrary(new Symbol(libraryName));
73+
74+
extractSymbols(lib);
75+
return names;
76+
}
77+
78+
describe('angular symbols', () {
79+
it('should not export symbols that we do not know about', () {
80+
var names;
81+
try { // Not impleneted in Dart VM 1.2
82+
names = _getSymbolsFromLibrary("angular");
83+
} finally {}
84+
85+
var ALLOWED_PREFIXS = [
86+
"Ng",
87+
"ng",
88+
"Angular",
89+
"_"
90+
];
91+
92+
var ALLOWED_NAMES = [
93+
"di.FactoryFn",
94+
"di.CreationStrategy",
95+
"di.Injector",
96+
"di.TypeFactory",
97+
"di.Visibility",
98+
"di.NoProviderError",
99+
"di.CircularDependencyError",
100+
"di.ObjectFactory",
101+
"di.Module",
102+
"angular.core.AnnotationMap",
103+
"angular.core.LruCache",
104+
"angular.core.ScopeStats",
105+
"angular.core.ArrayFn",
106+
"angular.core.Interpolation",
107+
"angular.core.LongStackTrace",
108+
"angular.core.Cache",
109+
"angular.core.ExpressionVisitor",
110+
"angular.core.ScopeEvent",
111+
"angular.core.MapFn",
112+
"angular.core.EvalFunction1",
113+
"angular.core.MetadataExtractor",
114+
"angular.core.ExceptionHandler",
115+
"angular.core.ZoneOnTurn",
116+
"angular.core.ZoneOnError",
117+
"angular.core.ScopeDigestTTL",
118+
"angular.core.EvalFunction0",
119+
"angular.core.AnnotationsMap",
120+
"angular.core.RootScope",
121+
"angular.core.CacheStats",
122+
"angular.core.ScopeLocals",
123+
"angular.core.ScopeStreamSubscription",
124+
"angular.core.Interpolate",
125+
"angular.core.NOT_IMPLEMENTED",
126+
"angular.core.Scope",
127+
"angular.core.AttrFieldAnnotation",
128+
"angular.core.UnboundedCache",
129+
"angular.core.ScopeStream",
130+
"angular.core.FilterMap",
131+
"angular.core.AstParser",
132+
"angular.watch_group.FunctionApply",
133+
"angular.watch_group.WatchGroup",
134+
"angular.watch_group.ContextReferenceAST",
135+
"angular.watch_group.ConstantAST",
136+
"angular.watch_group.Watch",
137+
"angular.watch_group.ReactionFn",
138+
"angular.watch_group.ChangeLog",
139+
"angular.watch_group.FieldReadAST",
140+
"angular.watch_group.PureFunctionAST",
141+
"angular.watch_group.PrototypeMap",
142+
"angular.watch_group.CollectionAST",
143+
"angular.watch_group.MethodAST",
144+
"angular.watch_group.AST",
145+
"angular.watch_group.RootWatchGroup",
146+
"angular.core.dom.AnimationResult",
147+
"angular.core.dom.WalkingViewFactory",
148+
"angular.core.dom.ResponseError",
149+
"angular.core.dom.View",
150+
"angular.core.dom.ElementBinder",
151+
"angular.core.dom.NoOpAnimation",
152+
"angular.core.dom.AttributeChanged",
153+
"angular.core.dom.HttpBackend",
154+
"angular.core.dom.HttpDefaults",
155+
"angular.core.dom.TaggedElementBinder",
156+
"angular.core.dom.LocationWrapper",
157+
"angular.core.dom.Cookies",
158+
"angular.core.dom.ElementBinderTreeRef",
159+
"angular.core.dom.EventHandler",
160+
"angular.core.dom.Response",
161+
"angular.core.dom.HttpDefaultHeaders",
162+
"angular.core.dom.Animation",
163+
"angular.core.dom.ViewPort",
164+
"angular.core.dom.TemplateLoader",
165+
"angular.core.dom.RequestErrorInterceptor",
166+
"angular.core.dom.TaggedTextBinder",
167+
"angular.core.dom.Http",
168+
"angular.core.dom.BoundViewFactory",
169+
"angular.core.dom.ElementBinderFactory",
170+
"angular.core.dom.DirectiveMap",
171+
"angular.core.dom.BrowserCookies",
172+
"angular.core.dom.HttpInterceptor",
173+
"angular.core.dom.cloneElements",
174+
"angular.core.dom.EventFunction",
175+
"angular.core.dom.RequestInterceptor",
176+
"angular.core.dom.DefaultTransformDataHttpInterceptor",
177+
"angular.core.dom.HttpResponseConfig",
178+
"angular.core.dom.ElementProbe",
179+
"angular.core.dom.ApplyMapping",
180+
"angular.core.dom.ViewCache",
181+
"angular.core.dom.FieldMetadataExtractor",
182+
"angular.core.dom.Compiler",
183+
"angular.core.dom.HttpResponse",
184+
"angular.core.dom.UrlRewriter",
185+
"angular.core.dom.DirectiveRef",
186+
"angular.core.dom.HttpInterceptors",
187+
"angular.core.dom.forceNewDirectivesAndFilters",
188+
"angular.core.dom.DirectiveSelectorFactory",
189+
"angular.core.dom.ObserverChanged",
190+
"angular.core.dom.TaggingViewFactory",
191+
"angular.core.dom.NodeCursor",
192+
"angular.core.dom.TemplateCache",
193+
"angular.core.dom.ViewFactory",
194+
"angular.core.dom.NullTreeSanitizer",
195+
"angular.core.dom.NodeAttrs",
196+
"angular.core.dom.ElementBinderTree",
197+
"angular.core.dom.WalkingCompiler",
198+
"angular.core.dom.TaggingCompiler",
199+
"angular.core.dom.DirectiveSelector",
200+
"angular.core.parser.BoundGetter",
201+
"angular.core.parser.LocalsWrapper",
202+
"angular.core.parser.Getter",
203+
"angular.core.parser.Parser",
204+
"angular.core.parser.ParserBackend",
205+
"angular.core.parser.BoundSetter",
206+
"angular.core.parser.Setter",
207+
"angular.core.parser.syntax.LiteralObject",
208+
"angular.core.parser.syntax.CallMember",
209+
"angular.core.parser.syntax.Filter",
210+
"angular.core.parser.syntax.defaultFilterMap",
211+
"angular.core.parser.syntax.BoundExpression",
212+
"angular.core.parser.syntax.AccessMember",
213+
"angular.core.parser.syntax.Expression",
214+
"angular.core.parser.syntax.AccessScope",
215+
"angular.core.parser.syntax.Assign",
216+
"angular.core.parser.syntax.AccessKeyed",
217+
"angular.core.parser.syntax.CallScope",
218+
"angular.core.parser.syntax.CallFunction",
219+
"angular.core.parser.syntax.Conditional",
220+
"angular.core.parser.syntax.Binary",
221+
"angular.core.parser.syntax.Chain",
222+
"angular.core.parser.syntax.Prefix",
223+
"angular.core.parser.syntax.Literal",
224+
"angular.core.parser.syntax.LiteralString",
225+
"angular.core.parser.syntax.LiteralArray",
226+
"angular.core.parser.syntax.LiteralPrimitive",
227+
"angular.core.parser.syntax.Visitor",
228+
"angular.core.parser.dynamic_parser.DynamicExpression",
229+
"angular.core.parser.dynamic_parser.ClosureMap",
230+
"angular.core.parser.dynamic_parser.DynamicParser",
231+
"angular.core.parser.dynamic_parser.DynamicParserBackend",
232+
"angular.core.parser.static_parser.StaticParserFunctions",
233+
"angular.core.parser.static_parser.StaticExpression",
234+
"angular.core.parser.static_parser.StaticParser",
235+
"angular.core.parser.lexer.Scanner",
236+
"angular.core.parser.lexer.OPERATORS",
237+
"angular.core.parser.lexer.NumberToken",
238+
"angular.core.parser.lexer.Token",
239+
"angular.core.parser.lexer.IdentifierToken",
240+
"angular.core.parser.lexer.StringToken",
241+
"angular.core.parser.lexer.CharacterToken",
242+
"angular.core.parser.lexer.Lexer",
243+
"angular.core.parser.lexer.KEYWORDS",
244+
"angular.core.parser.lexer.OperatorToken",
245+
"angular.directive.ItemEval",
246+
"angular.directive.OptionValueDirective",
247+
"angular.directive.InputSelectDirective",
248+
"angular.directive.InputTextLikeDirective",
249+
"angular.directive.InputNumberLikeDirective",
250+
"angular.directive.ContentEditableDirective",
251+
"angular.directive.InputCheckboxDirective",
252+
"angular.directive.InputRadioDirective",
253+
"angular.filter.JsonFilter",
254+
"angular.filter.Equals",
255+
"angular.filter.Mapper",
256+
"angular.filter.FilterFilter",
257+
"angular.filter.NumberFilter",
258+
"angular.filter.DateFilter",
259+
"angular.filter.LowercaseFilter",
260+
"angular.filter.UppercaseFilter",
261+
"angular.filter.OrderByFilter",
262+
"angular.filter.CurrencyFilter",
263+
"angular.filter.LimitToFilter",
264+
"angular.filter.Predicate",
265+
"angular.routing.RouteInitializerFn",
266+
"angular.routing.RouteProvider",
267+
"angular.routing.RouteInitializer",
268+
"angular.routing.RouteViewFactory",
269+
"route.client.RouteHandle",
270+
"route.client.RouteEnterEvent",
271+
"route.client.RouteStartEvent",
272+
"route.client.Router",
273+
"route.client.RouteEvent",
274+
"route.client.childRoute",
275+
"route.client.RouteLeaveEventHandler",
276+
"route.client.Route",
277+
"route.client.RouteLeaveEvent",
278+
"route.client.RoutePreEnterEventHandler",
279+
"route.client.RoutePreEnterEvent",
280+
"route.client.Routable",
281+
"route.client.RouteEnterEventHandler",
282+
"url_matcher.UrlMatcher",
283+
"url_matcher.UrlMatch",
284+
"dirty_checking_change_detector.FieldGetter",
285+
"dirty_checking_change_detector.DirtyCheckingChangeDetector",
286+
"dirty_checking_change_detector.DirtyCheckingRecord",
287+
"dirty_checking_change_detector.ItemRecord",
288+
"dirty_checking_change_detector.KeyValueRecord",
289+
"dirty_checking_change_detector.DuplicateMap",
290+
"dirty_checking_change_detector.GetterCache",
291+
"dirty_checking_change_detector.DirtyCheckingChangeDetectorGroup"
292+
];
293+
294+
var _nameMap = {};
295+
ALLOWED_NAMES.forEach((x) => _nameMap[x] = true);
296+
297+
var assertSymbolNameIsOk = (List nameInfo) {
298+
String name = nameInfo[0];
299+
String libName = nameInfo[1];
300+
301+
if (ALLOWED_PREFIXS.any((prefix) =>
302+
name.startsWith(prefix))) return;
303+
304+
var key = "$libName.$name";
305+
if (_nameMap.containsKey(key)) {
306+
_nameMap[key] = false;
307+
return;
308+
}
309+
310+
throw "Symbol $key is exported thru the angular library, but it shouldn't be";
311+
};
312+
313+
names.forEach(assertSymbolNameIsOk);
314+
315+
// If there are keys that no longer need to be in the ALLOWED_NAMES list, complain.
316+
_nameMap.forEach((k,v) {
317+
if (v) print("angular_spec.dart: Unused ALLOWED_NAMES key $k");
318+
});
319+
});
320+
});
43321
}

0 commit comments

Comments
 (0)