1
+ import TKUnit = require( "Tests/TKUnit" ) ;
2
+ import fs = require( "file-system" ) ;
3
+ import xmlModule = require( "xml" ) ;
4
+ import file_access_module = require( "file-system/file-system-access" ) ;
5
+ import types = require( "utils/types" ) ;
6
+ import app = require( "application" ) ;
7
+ import trace = require( "trace" ) ;
8
+
9
+ export var traceCategory = "definitionTest" ;
10
+
11
+ var ignoredModules = [
12
+ "camera" ,
13
+ "media-player" ,
14
+ "ui/pagesNew" ,
15
+ "ui/scroll-view" ,
16
+ "ui/slide-out" ,
17
+ "ui/web-view" ] ;
18
+
19
+ var whitelist = {
20
+ common : [
21
+ "Function not defined: application:.onLaunch" ,
22
+ "Function not defined: application:.onSuspend" ,
23
+ "Function not defined: application:.onResume" ,
24
+ "Function not defined: application:.onExit" ,
25
+ "Function not defined: application:.onLowMemory" ,
26
+ ] ,
27
+ android : [
28
+ "Variable not defined: application:.ios" ,
29
+ "Cannot find submodule: utils/utils:ios when searching for utils/utils:ios.collections.jsArrayToNSArray" ,
30
+ "Cannot find submodule: utils/utils:ios when searching for utils/utils:ios.collections.nsArrayToJSArray" ,
31
+ "Cannot find submodule: utils/utils:ios when searching for utils/utils:ios.getColor" ,
32
+ "Cannot find submodule: utils/utils:ios when searching for utils/utils:ios.getActualHeight" ] ,
33
+ ios : [
34
+ "Variable not defined: application:.android" ,
35
+ "Class not defined: ui/panels/panel:.NativePanel" ,
36
+ "Cannot find submodule: utils/utils:ad when searching for utils/utils:ad.collections.stringArrayToStringSet" ,
37
+ "Cannot find submodule: utils/utils:ad when searching for utils/utils:ad.collections.stringSetToStringArray" ,
38
+ "Cannot find submodule: utils/utils:ad when searching for utils/utils:ad.layout.UNSPECIFIED" ,
39
+ "Cannot find submodule: utils/utils:ad when searching for utils/utils:ad.layout.EXACTLY" ,
40
+ "Cannot find submodule: utils/utils:ad when searching for utils/utils:ad.layout.AT_MOST" ,
41
+ "Cannot find submodule: utils/utils:ad when searching for utils/utils:ad.layout.getMeasureSpecMode" ,
42
+ "Cannot find submodule: utils/utils:ad when searching for utils/utils:ad.layout.getMeasureSpecSize" ,
43
+ "Cannot find submodule: utils/utils:ad when searching for utils/utils:ad.layout.makeMeasureSpec" ,
44
+ "Cannot find submodule: utils/utils:ad when searching for utils/utils:ad.layout.getDisplayMetrics" ,
45
+ "Cannot find submodule: utils/utils:ad when searching for utils/utils:ad.layout.getDisplayDensity" ,
46
+ "Cannot find submodule: utils/utils:ad when searching for utils/utils:ad.layout.getDevicePixels" ,
47
+ "Cannot find submodule: utils/utils:ad when searching for utils/utils:ad.layout.getDeviceIndependentPixels" ,
48
+ "Cannot find submodule: utils/utils:ad when searching for utils/utils:ad.id.home" ,
49
+ "Cannot find submodule: utils/utils:ad when searching for utils/utils:ad.resources.getDrawableId" ,
50
+ "Cannot find submodule: utils/utils:ad when searching for utils/utils:ad.resources.getStringId" ,
51
+ "Cannot find submodule: utils/utils:ad when searching for utils/utils:ad.resources.getId" ,
52
+ "Cannot find submodule: utils/utils:ad when searching for utils/utils:ad.async" , ] ,
53
+ } ;
54
+
55
+ interface FuncInfo {
56
+ name : string ;
57
+ paramsCount : number
58
+ }
59
+
60
+ export var test_all_public_definitions_are_defined = function ( ) {
61
+ // Read specified CSS file from the current folder and assign it to the specified page
62
+ var path = fs . path . join ( fs . knownFolders . currentApp ( ) . path , "tns_modules" , "Tests" , "api.xml" ) ;
63
+
64
+ if ( ! fs . File . exists ( path ) ) {
65
+ throw new Error ( "api.xml file not found" ) ;
66
+ }
67
+
68
+ var fileAccess = new file_access_module . FileSystemAccess ( ) ;
69
+ var xml : string ;
70
+ // Read the XML file.
71
+ fileAccess . readText ( path , ( text ) => {
72
+ xml = text ;
73
+ } ) ;
74
+
75
+ parseAndTest ( xml )
76
+ } ;
77
+
78
+ function applyWhitelist ( erros : Array < string > ) : Array < string > {
79
+ var list = app . android ? whitelist . android : whitelist . ios ;
80
+ list = list . concat ( whitelist . common ) ;
81
+
82
+ return erros . filter ( ( val , index , all ) => {
83
+ return list . indexOf ( val ) < 0 ;
84
+ } ) ;
85
+ }
86
+
87
+ function parseAndTest ( xml : string ) {
88
+ var count : number = 0 ;
89
+ var moduleNesting = 0 ;
90
+ var currentModule = undefined ;
91
+ var currentModuleName : string = undefined ;
92
+
93
+ var subModuleStack = [ ] ;
94
+ var functionStack = new Array < FuncInfo > ( ) ;
95
+ var errors = new Array < string > ( ) ;
96
+
97
+ var getModuleToCheck = function ( name : string ) : Object {
98
+ var moduleToCheck = currentModule ;
99
+ for ( var i = 0 ; i < subModuleStack . length ; i ++ ) {
100
+ moduleToCheck = moduleToCheck [ subModuleStack [ i ] ] ;
101
+ if ( ! moduleToCheck ) {
102
+ var missingSubmodule = currentModuleName + ":" + subModuleStack . slice ( 0 , i + 1 ) . join ( "." ) ;
103
+ errors . push ( "Cannot find submodule: " + missingSubmodule + " when searching for " + getFullName ( name ) ) ;
104
+ return undefined ;
105
+ }
106
+ }
107
+
108
+ return moduleToCheck ;
109
+ }
110
+
111
+ var getFullName = function ( name : string ) {
112
+ if ( subModuleStack . length > 0 ) {
113
+ return currentModuleName + ":" + subModuleStack . join ( "." ) + "." + name ;
114
+ }
115
+ else {
116
+ return currentModuleName + ":" + "." + name ;
117
+ }
118
+ }
119
+
120
+ var getShortName = function ( name : string ) {
121
+ return name . substring ( name . lastIndexOf ( ":" ) + 1 , name . length ) ;
122
+ }
123
+
124
+ var checkFunction = function ( info : FuncInfo ) {
125
+ if ( ! info . name ) {
126
+ return ;
127
+ }
128
+
129
+ trace . write ( "Check function exists: " + getFullName ( info . name ) , traceCategory ) ;
130
+ var moduleToCheck = getModuleToCheck ( info . name ) ;
131
+ if ( moduleToCheck ) {
132
+ var actual = moduleToCheck [ info . name ] ;
133
+ if ( ! types . isFunction ( actual ) ) {
134
+ errors . push ( "Function not defined: " + getFullName ( info . name ) ) ;
135
+ }
136
+ else if ( actual . length !== info . paramsCount ) {
137
+ errors . push ( "Function " + getFullName ( info . name ) + " expected params: " + info . paramsCount + " actual params: " + actual . length ) ;
138
+ }
139
+ }
140
+ }
141
+
142
+ var checkClass = function ( className : string ) {
143
+ trace . write ( "Check class exists: " + getFullName ( className ) , traceCategory ) ;
144
+ var moduleToCheck = getModuleToCheck ( className ) ;
145
+ if ( moduleToCheck ) {
146
+ if ( ! types . isFunction ( moduleToCheck [ className ] ) ) {
147
+ errors . push ( "Class not defined: " + getFullName ( className ) ) ;
148
+ }
149
+ }
150
+ }
151
+
152
+ var checkVar = function ( varName : string ) {
153
+ trace . write ( "Check variable exists: " + getFullName ( varName ) , traceCategory ) ;
154
+ var moduleToCheck = getModuleToCheck ( varName ) ;
155
+ if ( moduleToCheck ) {
156
+ if ( ! types . isDefined ( moduleToCheck [ varName ] ) ) {
157
+ errors . push ( "Variable not defined: " + getFullName ( varName ) ) ;
158
+ }
159
+ }
160
+ }
161
+
162
+ var onEventCallback = function ( event : xmlModule . ParserEvent ) {
163
+ try {
164
+ switch ( event . eventType ) {
165
+
166
+ case xmlModule . ParserEventType . StartElement :
167
+ if ( event . elementName === "js:module" ) {
168
+ var moduleName : string = event . attributes [ "qname" ] ;
169
+
170
+ if ( moduleNesting === 0 ) {
171
+ moduleName = moduleName . replace ( / & q u o t ; / g, "" ) ;
172
+ if ( ignoredModules . indexOf ( moduleName ) < 0 ) {
173
+ currentModuleName = moduleName ;
174
+ trace . write ( "--- START CHECKING MODULE: " + currentModuleName , traceCategory ) ;
175
+ currentModule = require ( currentModuleName ) ;
176
+ }
177
+ }
178
+ else {
179
+ moduleName = getShortName ( moduleName ) ;
180
+ //trace.write("Push submodule: " + moduleName);
181
+ subModuleStack . push ( moduleName ) ;
182
+ }
183
+
184
+ moduleNesting ++ ;
185
+ }
186
+ else if ( event . elementName === "js:function" ) {
187
+ functionStack . push ( {
188
+ name : ( event . attributes && event . attributes [ "name" ] ) ? event . attributes [ "name" ] : undefined ,
189
+ paramsCount : 0
190
+ } ) ;
191
+ }
192
+ else if ( event . elementName === "js:param" && functionStack . length > 0 ) {
193
+ if ( ! event . attributes || event . attributes [ "rest" ] !== "true" ) {
194
+ functionStack [ functionStack . length - 1 ] . paramsCount ++ ;
195
+ }
196
+ }
197
+ else if ( event . elementName === "js:class" && event . attributes && event . attributes [ "qname" ] ) {
198
+ checkClass ( getShortName ( event . attributes [ "qname" ] ) ) ;
199
+ }
200
+
201
+ else if ( event . elementName === "js:var" && event . attributes && event . attributes [ "name" ] ) {
202
+ checkVar ( getShortName ( event . attributes [ "name" ] ) ) ;
203
+ }
204
+ break ;
205
+
206
+ case xmlModule . ParserEventType . EndElement :
207
+ if ( event . elementName === "js:module" ) {
208
+ moduleNesting -- ;
209
+ if ( moduleNesting === 0 ) {
210
+ trace . write ( "--- FINISHED CHECKING MODULE: " + currentModuleName , traceCategory ) ;
211
+ currentModule = undefined ;
212
+ currentModuleName = undefined ;
213
+ }
214
+ else {
215
+ var submodule = subModuleStack . pop ( ) ;
216
+ //trace.write("Pop submodule: " + submodule);
217
+ }
218
+ }
219
+ else if ( event . elementName === "js:function" ) {
220
+ checkFunction ( functionStack . pop ( ) ) ;
221
+ }
222
+
223
+ break ;
224
+ }
225
+ }
226
+ catch ( error ) {
227
+ errors . push ( "Error is event callback: " + error . message ) ;
228
+ }
229
+ } ;
230
+
231
+ var onErrorCallback = function ( error : Error ) {
232
+ errors . push ( "Error while parsing api.xml: " + error . message ) ;
233
+ } ;
234
+
235
+ var xmlParser = new xmlModule . XmlParser ( onEventCallback , onErrorCallback ) ;
236
+ xmlParser . parse ( xml ) ;
237
+
238
+ errors = applyWhitelist ( errors ) ;
239
+
240
+ TKUnit . assert ( errors . length == 0 , errors . join ( "\n" ) ) ;
241
+ }
0 commit comments