filewriter.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // Copyright 2011 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Mock FileWriter object.
  16. *
  17. */
  18. goog.setTestOnly('goog.testing.fs.FileWriter');
  19. goog.provide('goog.testing.fs.FileWriter');
  20. goog.require('goog.Timer');
  21. goog.require('goog.events.EventTarget');
  22. goog.require('goog.fs.Error');
  23. goog.require('goog.fs.FileSaver');
  24. goog.require('goog.string');
  25. goog.require('goog.testing.fs.ProgressEvent');
  26. /**
  27. * A mock FileWriter object. This emits the same events as
  28. * {@link goog.fs.FileSaver} and {@link goog.fs.FileWriter}.
  29. *
  30. * @param {!goog.testing.fs.FileEntry} fileEntry The file entry to write to.
  31. * @constructor
  32. * @extends {goog.events.EventTarget}
  33. * @final
  34. */
  35. goog.testing.fs.FileWriter = function(fileEntry) {
  36. goog.testing.fs.FileWriter.base(this, 'constructor');
  37. /**
  38. * The file entry to which to write.
  39. * @type {!goog.testing.fs.FileEntry}
  40. * @private
  41. */
  42. this.fileEntry_ = fileEntry;
  43. /**
  44. * The file blob to write to.
  45. * @type {!goog.testing.fs.File}
  46. * @private
  47. */
  48. this.file_ = fileEntry.fileSync();
  49. /**
  50. * The current state of the writer.
  51. * @type {goog.fs.FileSaver.ReadyState}
  52. * @private
  53. */
  54. this.readyState_ = goog.fs.FileSaver.ReadyState.INIT;
  55. };
  56. goog.inherits(goog.testing.fs.FileWriter, goog.events.EventTarget);
  57. /**
  58. * The most recent error experienced by this writer.
  59. * @type {goog.fs.Error}
  60. * @private
  61. */
  62. goog.testing.fs.FileWriter.prototype.error_;
  63. /**
  64. * Whether the current operation has been aborted.
  65. * @type {boolean}
  66. * @private
  67. */
  68. goog.testing.fs.FileWriter.prototype.aborted_ = false;
  69. /**
  70. * The current position in the file.
  71. * @type {number}
  72. * @private
  73. */
  74. goog.testing.fs.FileWriter.prototype.position_ = 0;
  75. /**
  76. * @see {goog.fs.FileSaver#getReadyState}
  77. * @return {goog.fs.FileSaver.ReadyState} The ready state.
  78. */
  79. goog.testing.fs.FileWriter.prototype.getReadyState = function() {
  80. return this.readyState_;
  81. };
  82. /**
  83. * @see {goog.fs.FileSaver#getError}
  84. * @return {goog.fs.Error} The error.
  85. */
  86. goog.testing.fs.FileWriter.prototype.getError = function() {
  87. return this.error_;
  88. };
  89. /**
  90. * @see {goog.fs.FileWriter#getPosition}
  91. * @return {number} The position.
  92. */
  93. goog.testing.fs.FileWriter.prototype.getPosition = function() {
  94. return this.position_;
  95. };
  96. /**
  97. * @see {goog.fs.FileWriter#getLength}
  98. * @return {number} The length.
  99. */
  100. goog.testing.fs.FileWriter.prototype.getLength = function() {
  101. return this.file_.size;
  102. };
  103. /**
  104. * @see {goog.fs.FileSaver#abort}
  105. */
  106. goog.testing.fs.FileWriter.prototype.abort = function() {
  107. if (this.readyState_ != goog.fs.FileSaver.ReadyState.WRITING) {
  108. var msg = 'aborting save of ' + this.fileEntry_.getFullPath();
  109. throw new goog.fs.Error({'name': 'InvalidStateError'}, msg);
  110. }
  111. this.aborted_ = true;
  112. };
  113. /**
  114. * @see {goog.fs.FileWriter#write}
  115. * @param {!goog.testing.fs.Blob} blob The blob to write.
  116. */
  117. goog.testing.fs.FileWriter.prototype.write = function(blob) {
  118. if (this.readyState_ == goog.fs.FileSaver.ReadyState.WRITING) {
  119. var msg = 'writing to ' + this.fileEntry_.getFullPath();
  120. throw new goog.fs.Error({'name': 'InvalidStateError'}, msg);
  121. }
  122. this.readyState_ = goog.fs.FileSaver.ReadyState.WRITING;
  123. goog.Timer.callOnce(function() {
  124. if (this.aborted_) {
  125. this.abort_(blob.size);
  126. return;
  127. }
  128. this.progressEvent_(goog.fs.FileSaver.EventType.WRITE_START, 0, blob.size);
  129. var fileString = this.file_.toString();
  130. this.file_.setDataInternal(
  131. fileString.substring(0, this.position_) + blob.toString() +
  132. fileString.substring(this.position_ + blob.size, fileString.length));
  133. this.position_ += blob.size;
  134. this.progressEvent_(
  135. goog.fs.FileSaver.EventType.WRITE, blob.size, blob.size);
  136. this.readyState_ = goog.fs.FileSaver.ReadyState.DONE;
  137. this.progressEvent_(
  138. goog.fs.FileSaver.EventType.WRITE_END, blob.size, blob.size);
  139. }, 0, this);
  140. };
  141. /**
  142. * @see {goog.fs.FileWriter#truncate}
  143. * @param {number} size The size to truncate to.
  144. */
  145. goog.testing.fs.FileWriter.prototype.truncate = function(size) {
  146. if (this.readyState_ == goog.fs.FileSaver.ReadyState.WRITING) {
  147. var msg = 'truncating ' + this.fileEntry_.getFullPath();
  148. throw new goog.fs.Error({'name': 'InvalidStateError'}, msg);
  149. }
  150. this.readyState_ = goog.fs.FileSaver.ReadyState.WRITING;
  151. goog.Timer.callOnce(function() {
  152. if (this.aborted_) {
  153. this.abort_(size);
  154. return;
  155. }
  156. this.progressEvent_(goog.fs.FileSaver.EventType.WRITE_START, 0, size);
  157. var fileString = this.file_.toString();
  158. if (size > fileString.length) {
  159. this.file_.setDataInternal(
  160. fileString + goog.string.repeat('\0', size - fileString.length));
  161. } else {
  162. this.file_.setDataInternal(fileString.substring(0, size));
  163. }
  164. this.position_ = Math.min(this.position_, size);
  165. this.progressEvent_(goog.fs.FileSaver.EventType.WRITE, size, size);
  166. this.readyState_ = goog.fs.FileSaver.ReadyState.DONE;
  167. this.progressEvent_(goog.fs.FileSaver.EventType.WRITE_END, size, size);
  168. }, 0, this);
  169. };
  170. /**
  171. * @see {goog.fs.FileWriter#seek}
  172. * @param {number} offset The offset to seek to.
  173. */
  174. goog.testing.fs.FileWriter.prototype.seek = function(offset) {
  175. if (this.readyState_ == goog.fs.FileSaver.ReadyState.WRITING) {
  176. var msg = 'truncating ' + this.fileEntry_.getFullPath();
  177. throw new goog.fs.Error({name: 'InvalidStateError'}, msg);
  178. }
  179. if (offset < 0) {
  180. this.position_ = Math.max(0, this.file_.size + offset);
  181. } else {
  182. this.position_ = Math.min(offset, this.file_.size);
  183. }
  184. };
  185. /**
  186. * Abort the current action and emit appropriate events.
  187. *
  188. * @param {number} total The total data that was to be processed, in bytes.
  189. * @private
  190. */
  191. goog.testing.fs.FileWriter.prototype.abort_ = function(total) {
  192. this.error_ = new goog.fs.Error(
  193. {'name': 'AbortError'}, 'saving ' + this.fileEntry_.getFullPath());
  194. this.progressEvent_(goog.fs.FileSaver.EventType.ERROR, 0, total);
  195. this.progressEvent_(goog.fs.FileSaver.EventType.ABORT, 0, total);
  196. this.readyState_ = goog.fs.FileSaver.ReadyState.DONE;
  197. this.progressEvent_(goog.fs.FileSaver.EventType.WRITE_END, 0, total);
  198. this.aborted_ = false;
  199. };
  200. /**
  201. * Dispatch a progress event.
  202. *
  203. * @param {goog.fs.FileSaver.EventType} type The type of the event.
  204. * @param {number} loaded The number of bytes processed.
  205. * @param {number} total The total data that was to be processed, in bytes.
  206. * @private
  207. */
  208. goog.testing.fs.FileWriter.prototype.progressEvent_ = function(
  209. type, loaded, total) {
  210. // On write, update the last modified date to the current (real or mock) time.
  211. if (type == goog.fs.FileSaver.EventType.WRITE) {
  212. this.file_.lastModifiedDate = new Date(goog.now());
  213. }
  214. this.dispatchEvent(new goog.testing.fs.ProgressEvent(type, loaded, total));
  215. };