model.spec.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import expect = require('expect.js');
  4. import {
  5. IChangedArgs
  6. } from '../../../../lib/common/interfaces';
  7. import {
  8. nbformat
  9. } from '../../../../lib/notebook/notebook/nbformat';
  10. import {
  11. CellModel, RawCellModel, MarkdownCellModel, CodeCellModel
  12. } from '../../../../lib/notebook/cells';
  13. import {
  14. OutputAreaModel
  15. } from '../../../../lib/notebook/output-area';
  16. class TestModel extends CellModel {
  17. get type(): 'raw' { return 'raw'; }
  18. setCursorData(name: string, newValue: any): void {
  19. super.setCursorData(name, newValue);
  20. }
  21. }
  22. describe('notebook/cells/model', () => {
  23. describe('CellModel', () => {
  24. describe('#constructor()', () => {
  25. it('should create a cell model', () => {
  26. let model = new CellModel();
  27. expect(model).to.be.a(CellModel);
  28. });
  29. it('should accept a base cell argument', () => {
  30. let base: nbformat.IBaseCell = {
  31. cell_type: 'raw',
  32. source: 'foo',
  33. metadata: { trusted: false }
  34. };
  35. let model = new CellModel(base);
  36. expect(model).to.be.a(CellModel);
  37. expect(model.source).to.equal(base.source);
  38. });
  39. it('should accept a base cell argument with a multiline source', () => {
  40. let base: nbformat.IBaseCell = {
  41. cell_type: 'raw',
  42. source: ['foo', 'bar', 'baz'],
  43. metadata: { trusted: false }
  44. };
  45. let model = new CellModel(base);
  46. expect(model).to.be.a(CellModel);
  47. expect(model.source).to.equal((base.source as string[]).join('\n'));
  48. });
  49. });
  50. describe('#contentChanged', () => {
  51. it('should signal when model content has changed', () => {
  52. let model = new CellModel();
  53. let called = false;
  54. model.contentChanged.connect(() => { called = true; });
  55. expect(called).to.be(false);
  56. model.source = 'foo';
  57. expect(called).to.be(true);
  58. });
  59. });
  60. describe('#stateChanged', () => {
  61. it('should signal when model state has changed', () => {
  62. let model = new CellModel();
  63. let listener = (sender: any, args: IChangedArgs<any>) => {
  64. value = args.newValue;
  65. };
  66. let value = '';
  67. model.stateChanged.connect(listener);
  68. expect(value).to.be.empty();
  69. model.source = 'foo';
  70. expect(value).to.be(model.source);
  71. });
  72. it('should not signal when model state has not changed', () => {
  73. let model = new CellModel();
  74. let called = 0;
  75. model.stateChanged.connect(() => { called++; });
  76. expect(called).to.be(0);
  77. model.source = 'foo';
  78. expect(called).to.be(1);
  79. model.source = 'foo';
  80. expect(called).to.be(1);
  81. });
  82. });
  83. describe('#metadataChanged', () => {
  84. it('should signal when model metadata has changed', () => {
  85. let model = new TestModel();
  86. let listener = (sender: any, args: IChangedArgs<any>) => {
  87. value = args.newValue;
  88. };
  89. let value = '';
  90. model.metadataChanged.connect(listener);
  91. expect(value).to.be.empty();
  92. model.setCursorData('foo', 'bar');
  93. expect(value).to.be('bar');
  94. });
  95. it('should not signal when model metadata has not changed', () => {
  96. let model = new TestModel();
  97. let called = 0;
  98. model.metadataChanged.connect(() => { called++; });
  99. expect(called).to.be(0);
  100. model.setCursorData('foo', 'bar');
  101. expect(called).to.be(1);
  102. model.setCursorData('foo', 'bar');
  103. expect(called).to.be(1);
  104. });
  105. });
  106. describe('#source', () => {
  107. it('should default to an empty string', () => {
  108. let model = new CellModel();
  109. expect(model.source).to.be.empty();
  110. });
  111. it('should be settable', () => {
  112. let model = new CellModel();
  113. expect(model.source).to.be.empty();
  114. model.source = 'foo';
  115. expect(model.source).to.be('foo');
  116. });
  117. });
  118. describe('#isDisposed', () => {
  119. it('should be false by default', () => {
  120. let model = new CellModel();
  121. expect(model.isDisposed).to.be(false);
  122. });
  123. it('should be true after model is disposed', () => {
  124. let model = new CellModel();
  125. model.dispose();
  126. expect(model.isDisposed).to.be(true);
  127. });
  128. });
  129. describe('#dispose()', () => {
  130. it('should dispose of the resources held by the model', () => {
  131. let model = new TestModel();
  132. model.setCursorData('foo', 'bar');
  133. expect(model.getMetadata('foo').getValue()).to.be('bar');
  134. model.dispose();
  135. expect(model.isDisposed).to.be(true);
  136. expect(model.getMetadata('foo')).to.be(null);
  137. });
  138. it('should be safe to call multiple times', () => {
  139. let model = new CellModel();
  140. model.dispose();
  141. model.dispose();
  142. expect(model.isDisposed).to.be(true);
  143. });
  144. });
  145. describe('#toJSON()', () => {
  146. it('should return a base cell encapsulation of the model value', () => {
  147. let base: nbformat.IBaseCell = {
  148. cell_type: 'raw',
  149. source: 'foo',
  150. metadata: { trusted: false }
  151. };
  152. let model = new TestModel(base);
  153. expect(model.toJSON()).to.not.equal(base);
  154. expect(model.toJSON()).to.eql(base);
  155. });
  156. it('should always return a string source', () => {
  157. let base: nbformat.IBaseCell = {
  158. cell_type: 'raw',
  159. source: ['foo', 'bar', 'baz'],
  160. metadata: { trusted: false }
  161. };
  162. let model = new TestModel(base);
  163. base.source = (base.source as string[]).join('\n');
  164. expect(model.toJSON()).to.not.equal(base);
  165. expect(model.toJSON()).to.eql(base);
  166. });
  167. });
  168. describe('#getMetadata()', () => {
  169. it('should get a metadata cursor for the cell', () => {
  170. let model = new CellModel();
  171. let c1 = model.getMetadata('foo');
  172. expect(c1.getValue()).to.be(void 0);
  173. c1.setValue(1);
  174. expect(c1.getValue()).to.be(1);
  175. let c2 = model.getMetadata('foo');
  176. expect(c2.getValue()).to.be(1);
  177. c2.setValue(2);
  178. expect(c1.getValue()).to.be(2);
  179. expect(c2.getValue()).to.be(2);
  180. });
  181. });
  182. describe('#listMetadata()', () => {
  183. it('should get a list of user metadata keys', () => {
  184. let model = new CellModel();
  185. let cursor = model.getMetadata('foo');
  186. expect(model.listMetadata()).to.be.empty();
  187. cursor.setValue(1);
  188. expect(model.listMetadata()).to.eql(['foo']);
  189. });
  190. });
  191. });
  192. describe('RawCellModel', () => {
  193. describe('#type', () => {
  194. it('should be set with type "raw"', () => {
  195. let model = new RawCellModel();
  196. expect(model.type).to.be('raw');
  197. });
  198. });
  199. });
  200. describe('MarkdownCellModel', () => {
  201. describe('#type', () => {
  202. it('should be set with type "markdown"', () => {
  203. let model = new MarkdownCellModel();
  204. expect(model.type).to.be('markdown');
  205. });
  206. });
  207. });
  208. describe('CodeCellModel', () => {
  209. describe('#constructor()', () => {
  210. it('should create a code cell model', () => {
  211. let model = new CodeCellModel();
  212. expect(model).to.be.a(CodeCellModel);
  213. });
  214. it('should accept a code cell argument', () => {
  215. let cell: nbformat.ICodeCell = {
  216. cell_type: 'code',
  217. execution_count: 1,
  218. outputs: [
  219. {
  220. output_type: 'display_data',
  221. data: { 'text/plain': 'foo' },
  222. metadata: {}
  223. } as nbformat.IDisplayData
  224. ],
  225. source: 'foo',
  226. metadata: { trusted: false }
  227. };
  228. let model = new CodeCellModel(cell);
  229. expect(model).to.be.a(CodeCellModel);
  230. expect(model.source).to.equal(cell.source);
  231. });
  232. it('should connect the outputs changes to content change signal', () => {
  233. let data = {
  234. output_type: 'display_data',
  235. data: { 'text/plain': 'foo' },
  236. metadata: {}
  237. } as nbformat.IDisplayData;
  238. let model = new CodeCellModel();
  239. let called = false;
  240. model.contentChanged.connect(() => { called = true; });
  241. expect(called).to.be(false);
  242. model.outputs.add(data);
  243. expect(called).to.be(true);
  244. });
  245. });
  246. describe('#type', () => {
  247. it('should be set with type "code"', () => {
  248. let model = new CodeCellModel();
  249. expect(model.type).to.be('code');
  250. });
  251. });
  252. describe('#executionCount', () => {
  253. it('should show the execution count of the cell', () => {
  254. let cell: nbformat.ICodeCell = {
  255. cell_type: 'code',
  256. execution_count: 1,
  257. outputs: [],
  258. source: 'foo',
  259. metadata: { trusted: false }
  260. };
  261. let model = new CodeCellModel(cell);
  262. expect(model.executionCount).to.be(1);
  263. });
  264. it('should be settable', () => {
  265. let model = new CodeCellModel();
  266. expect(model.executionCount).to.be(null);
  267. model.executionCount = 1;
  268. expect(model.executionCount).to.be(1);
  269. });
  270. it('should emit a state change signal when set', () => {
  271. let model = new CodeCellModel();
  272. let called = false;
  273. model.stateChanged.connect(() => { called = true; });
  274. expect(model.executionCount).to.be(null);
  275. expect(called).to.be(false);
  276. model.executionCount = 1;
  277. expect(model.executionCount).to.be(1);
  278. expect(called).to.be(true);
  279. });
  280. it('should not signal when state has not changed', () => {
  281. let model = new CodeCellModel();
  282. let called = 0;
  283. model.stateChanged.connect(() => { called++; });
  284. expect(model.executionCount).to.be(null);
  285. expect(called).to.be(0);
  286. model.executionCount = 1;
  287. expect(model.executionCount).to.be(1);
  288. model.executionCount = 1;
  289. expect(called).to.be(1);
  290. });
  291. });
  292. describe('#outputs', () => {
  293. it('should be an output area model', () => {
  294. let model = new CodeCellModel();
  295. expect(model.outputs).to.be.an(OutputAreaModel);
  296. });
  297. });
  298. describe('#dispose()', () => {
  299. it('should dispose of the resources held by the model', () => {
  300. let model = new CodeCellModel();
  301. expect(model.outputs).to.be.an(OutputAreaModel);
  302. model.dispose();
  303. expect(model.isDisposed).to.be(true);
  304. expect(model.outputs).to.be(null);
  305. });
  306. it('should be safe to call multiple times', () => {
  307. let model = new CodeCellModel();
  308. model.dispose();
  309. model.dispose();
  310. expect(model.isDisposed).to.be(true);
  311. });
  312. });
  313. describe('#toJSON()', () => {
  314. it('should return a code cell encapsulation of the model value', () => {
  315. let cell: nbformat.ICodeCell = {
  316. cell_type: 'code',
  317. execution_count: 1,
  318. outputs: [
  319. {
  320. output_type: 'display_data',
  321. data: { 'text/plain': 'foo' },
  322. metadata: {}
  323. } as nbformat.IDisplayData
  324. ],
  325. source: 'foo',
  326. metadata: { trusted: false }
  327. };
  328. let model = new CodeCellModel(cell);
  329. expect(model.toJSON()).to.not.equal(cell);
  330. expect(model.toJSON()).to.eql(cell);
  331. });
  332. });
  333. });
  334. });