Repositorio del curso CCOM4030 el semestre B91 del proyecto Artesanías con el Instituto de Cultura

ProjectBuilder.spec.js 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. /*
  2. Licensed to the Apache Software Foundation (ASF) under one
  3. or more contributor license agreements. See the NOTICE file
  4. distributed with this work for additional information
  5. regarding copyright ownership. The ASF licenses this file
  6. to you under the Apache License, Version 2.0 (the
  7. "License"); you may not use this file except in compliance
  8. with the License. You may obtain a copy of the License at
  9. http://www.apache.org/licenses/LICENSE-2.0
  10. Unless required by applicable law or agreed to in writing,
  11. software distributed under the License is distributed on an
  12. "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  13. KIND, either express or implied. See the License for the
  14. specific language governing permissions and limitations
  15. under the License.
  16. */
  17. const fs = require('fs');
  18. const path = require('path');
  19. const Q = require('q');
  20. const rewire = require('rewire');
  21. const CordovaError = require('cordova-common').CordovaError;
  22. describe('ProjectBuilder', () => {
  23. const rootDir = '/root';
  24. let builder;
  25. let ProjectBuilder;
  26. let spawnSpy;
  27. beforeEach(() => {
  28. spawnSpy = jasmine.createSpy('spawn').and.returnValue(Q.defer().promise);
  29. ProjectBuilder = rewire('../../../bin/templates/cordova/lib/builders/ProjectBuilder');
  30. ProjectBuilder.__set__('spawn', spawnSpy);
  31. builder = new ProjectBuilder(rootDir);
  32. });
  33. describe('constructor', () => {
  34. it('should set the project directory to the passed argument', () => {
  35. expect(builder.root).toBe(rootDir);
  36. });
  37. it('should set the project directory to three folders up', () => {
  38. ProjectBuilder.__set__('__dirname', 'projecttest/platforms/android/app');
  39. builder = new ProjectBuilder();
  40. expect(builder.root).toMatch(/projecttest$/);
  41. });
  42. });
  43. describe('getArgs', () => {
  44. beforeEach(() => {
  45. spyOn(fs, 'existsSync').and.returnValue(true);
  46. });
  47. it('should set release argument', () => {
  48. const args = builder.getArgs('release', {});
  49. expect(args[0]).toBe('cdvBuildRelease');
  50. });
  51. it('should set debug argument', () => {
  52. const args = builder.getArgs('debug', {});
  53. expect(args[0]).toBe('cdvBuildDebug');
  54. });
  55. it('should set apk release', () => {
  56. const args = builder.getArgs('release', {
  57. packageType: 'apk'
  58. });
  59. expect(args[0]).withContext(args).toBe('cdvBuildRelease');
  60. });
  61. it('should set apk debug', () => {
  62. const args = builder.getArgs('debug', {
  63. packageType: 'apk'
  64. });
  65. expect(args[0]).withContext(args).toBe('cdvBuildDebug');
  66. });
  67. it('should set bundle release', () => {
  68. const args = builder.getArgs('release', {
  69. packageType: 'bundle'
  70. });
  71. expect(args[0]).withContext(args).toBe(':app:bundleRelease');
  72. });
  73. it('should set bundle debug', () => {
  74. const args = builder.getArgs('debug', {
  75. packageType: 'bundle'
  76. });
  77. expect(args[0]).withContext(args).toBe(':app:bundleDebug');
  78. });
  79. it('should add architecture if it is passed', () => {
  80. const arch = 'unittest';
  81. const args = builder.getArgs('debug', { arch });
  82. expect(args).toContain(`-PcdvBuildArch=${arch}`);
  83. });
  84. it('should clean apk', () => {
  85. const args = builder.getArgs('clean', {
  86. packageType: 'apk'
  87. });
  88. expect(args[0]).toBe('clean');
  89. });
  90. it('should clean bundle', () => {
  91. const args = builder.getArgs('clean', {
  92. packageType: 'bundle'
  93. });
  94. expect(args[0]).toBe('clean');
  95. });
  96. });
  97. describe('runGradleWrapper', () => {
  98. it('should run the provided gradle command if a gradle wrapper does not already exist', () => {
  99. spyOn(fs, 'existsSync').and.returnValue(false);
  100. builder.runGradleWrapper('/my/sweet/gradle');
  101. expect(spawnSpy).toHaveBeenCalledWith('/my/sweet/gradle', jasmine.any(Array), jasmine.any(Object));
  102. });
  103. it('should do nothing if a gradle wrapper exists in the project directory', () => {
  104. spyOn(fs, 'existsSync').and.returnValue(true);
  105. builder.runGradleWrapper('/my/sweet/gradle');
  106. expect(spawnSpy).not.toHaveBeenCalledWith('/my/sweet/gradle', jasmine.any(Array), jasmine.any(Object));
  107. });
  108. });
  109. describe('extractRealProjectNameFromManifest', () => {
  110. it('should get the project name from the Android Manifest', () => {
  111. const projectName = 'unittestproject';
  112. const projectId = `io.cordova.${projectName}`;
  113. const manifest = `<?xml version="1.0" encoding="utf-8"?>
  114. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  115. package="${projectId}"></manifest>`;
  116. spyOn(fs, 'readFileSync').and.returnValue(manifest);
  117. expect(builder.extractRealProjectNameFromManifest()).toBe(projectName);
  118. });
  119. it('should throw an error if there is no package in the Android manifest', () => {
  120. const manifest = `<?xml version="1.0" encoding="utf-8"?>
  121. <manifest xmlns:android="http://schemas.android.com/apk/res/android"></manifest>`;
  122. spyOn(fs, 'readFileSync').and.returnValue(manifest);
  123. expect(() => builder.extractRealProjectNameFromManifest()).toThrow(jasmine.any(CordovaError));
  124. });
  125. });
  126. describe('build', () => {
  127. beforeEach(() => {
  128. spyOn(builder, 'getArgs');
  129. });
  130. it('should set build type to debug', () => {
  131. const opts = { buildType: 'debug' };
  132. builder.build(opts);
  133. expect(builder.getArgs).toHaveBeenCalledWith('debug', opts);
  134. });
  135. it('should set build type to release', () => {
  136. const opts = { buildType: 'release' };
  137. builder.build(opts);
  138. expect(builder.getArgs).toHaveBeenCalledWith('release', opts);
  139. });
  140. it('should default build type to release', () => {
  141. const opts = {};
  142. builder.build(opts);
  143. expect(builder.getArgs).toHaveBeenCalledWith('release', opts);
  144. });
  145. it('should spawn gradle with correct args', () => {
  146. const testArgs = ['test', 'args', '-c'];
  147. builder.getArgs.and.returnValue(testArgs);
  148. builder.build({});
  149. expect(spawnSpy).toHaveBeenCalledWith(path.join(rootDir, 'gradlew'), testArgs, jasmine.anything());
  150. });
  151. it('should reject if the spawn fails', () => {
  152. const errorMessage = 'ERROR: Failed to spawn';
  153. spawnSpy.and.returnValue(Q.reject(errorMessage));
  154. return builder.build({}).then(
  155. () => fail('Unexpectedly resolved'),
  156. err => {
  157. expect(err).toBe(errorMessage);
  158. }
  159. );
  160. });
  161. it('should check the Android target if failed to find target', () => {
  162. const checkReqsSpy = jasmine.createSpyObj('check_reqs', ['check_android_target']);
  163. const errorMessage = 'ERROR: failed to find target with hash string';
  164. ProjectBuilder.__set__('check_reqs', checkReqsSpy);
  165. checkReqsSpy.check_android_target.and.returnValue(Q.resolve());
  166. spawnSpy.and.returnValue(Q.reject(errorMessage));
  167. return builder.build({}).then(
  168. () => fail('Unexpectedly resolved'),
  169. err => {
  170. expect(checkReqsSpy.check_android_target).toHaveBeenCalledWith(errorMessage);
  171. expect(err).toBe(errorMessage);
  172. }
  173. );
  174. });
  175. });
  176. describe('clean', () => {
  177. let shellSpy;
  178. beforeEach(() => {
  179. shellSpy = jasmine.createSpyObj('shell', ['rm']);
  180. ProjectBuilder.__set__('shell', shellSpy);
  181. spyOn(builder, 'getArgs');
  182. spawnSpy.and.returnValue(Promise.resolve());
  183. });
  184. it('should get arguments for cleaning', () => {
  185. const opts = {};
  186. builder.clean(opts);
  187. expect(builder.getArgs).toHaveBeenCalledWith('clean', opts);
  188. });
  189. it('should spawn gradle', () => {
  190. const opts = {};
  191. const gradleArgs = ['test', 'args', '-f'];
  192. builder.getArgs.and.returnValue(gradleArgs);
  193. return builder.clean(opts).then(() => {
  194. expect(spawnSpy).toHaveBeenCalledWith(path.join(rootDir, 'gradlew'), gradleArgs, jasmine.anything());
  195. });
  196. });
  197. it('should remove "out" folder', () => {
  198. return builder.clean({}).then(() => {
  199. expect(shellSpy.rm).toHaveBeenCalledWith('-rf', path.join(rootDir, 'out'));
  200. });
  201. });
  202. it('should remove signing files if they are autogenerated', () => {
  203. const debugSigningFile = path.join(rootDir, 'debug-signing.properties');
  204. const releaseSigningFile = path.join(rootDir, 'release-signing.properties');
  205. const isAutoGeneratedSpy = jasmine.createSpy('isAutoGenerated');
  206. ProjectBuilder.__set__('isAutoGenerated', isAutoGeneratedSpy);
  207. isAutoGeneratedSpy.and.returnValue(true);
  208. return builder.clean({}).then(() => {
  209. expect(shellSpy.rm).toHaveBeenCalledWith(jasmine.any(String), debugSigningFile);
  210. expect(shellSpy.rm).toHaveBeenCalledWith(jasmine.any(String), releaseSigningFile);
  211. });
  212. });
  213. it('should not remove signing files if they are not autogenerated', () => {
  214. const debugSigningFile = path.join(rootDir, 'debug-signing.properties');
  215. const releaseSigningFile = path.join(rootDir, 'release-signing.properties');
  216. const isAutoGeneratedSpy = jasmine.createSpy('isAutoGenerated');
  217. ProjectBuilder.__set__('isAutoGenerated', isAutoGeneratedSpy);
  218. isAutoGeneratedSpy.and.returnValue(false);
  219. return builder.clean({}).then(() => {
  220. expect(shellSpy.rm).not.toHaveBeenCalledWith(jasmine.any(String), debugSigningFile);
  221. expect(shellSpy.rm).not.toHaveBeenCalledWith(jasmine.any(String), releaseSigningFile);
  222. });
  223. });
  224. });
  225. describe('apkSorter', () => {
  226. it('should sort APKs from most recent to oldest, deprioritising unsigned arch-specific builds', () => {
  227. const APKs = {
  228. 'app-debug.apk': new Date('2018-04-20'),
  229. 'app-release.apk': new Date('2018-05-20'),
  230. 'app-debug-x86.apk': new Date('2018-06-01'),
  231. 'app-release-x86.apk': new Date('2018-06-20'),
  232. 'app-debug-arm.apk': new Date('2018-05-24'),
  233. 'app-release-arm.apk': new Date('2018-06-24'),
  234. 'app-release-unsigned.apk': new Date('2018-06-28')
  235. };
  236. const expectedResult = ['app-release.apk', 'app-debug.apk', 'app-release-unsigned.apk',
  237. 'app-release-arm.apk', 'app-release-x86.apk', 'app-debug-x86.apk', 'app-debug-arm.apk'];
  238. const fsSpy = jasmine.createSpyObj('fs', ['statSync']);
  239. fsSpy.statSync.and.callFake(filename => {
  240. return { mtime: APKs[filename] };
  241. });
  242. ProjectBuilder.__set__('fs', fsSpy);
  243. const apkArray = Object.keys(APKs);
  244. const sortedApks = apkArray.sort(ProjectBuilder.__get__('apkSorter'));
  245. expect(sortedApks).toEqual(expectedResult);
  246. });
  247. });
  248. describe('isAutoGenerated', () => {
  249. let fsSpy;
  250. beforeEach(() => {
  251. fsSpy = jasmine.createSpyObj('fs', ['existsSync', 'readFileSync']);
  252. fsSpy.existsSync.and.returnValue(true);
  253. ProjectBuilder.__set__('fs', fsSpy);
  254. });
  255. it('should return true if the file contains the autogenerated marker', () => {
  256. const fileContents = `# DO NOT MODIFY - YOUR CHANGES WILL BE ERASED!`;
  257. fsSpy.readFileSync.and.returnValue(fileContents);
  258. expect(ProjectBuilder.__get__('isAutoGenerated')()).toBe(true);
  259. });
  260. it('should return false if the file does not contain the autogenerated marker', () => {
  261. const fileContents = `# My modified file`;
  262. fsSpy.readFileSync.and.returnValue(fileContents);
  263. expect(ProjectBuilder.__get__('isAutoGenerated')()).toBe(false);
  264. });
  265. });
  266. });