range.test.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. 'use strict'
  2. const { expect } = require('chai')
  3. const Range = require('../../lib/range')
  4. describe('Range', function () {
  5. it('should create a range', function () {
  6. const from5to14 = new Range(5, 10)
  7. expect(from5to14.start).to.eql(5)
  8. expect(from5to14.end).to.eql(15)
  9. })
  10. it('should create a range using fromRaw', function () {
  11. const from5to14 = Range.fromRaw({ pos: 5, length: 10 })
  12. expect(from5to14.start).to.eql(5)
  13. expect(from5to14.end).to.eql(15)
  14. })
  15. it('should convert to raw', function () {
  16. const from5to14 = new Range(5, 10)
  17. expect(from5to14.toRaw()).to.eql({ pos: 5, length: 10 })
  18. })
  19. it('should check isEmpty method', function () {
  20. const from5to14 = new Range(5, 10)
  21. expect(from5to14.isEmpty()).to.be.false
  22. const range0length = new Range(5, 0)
  23. expect(range0length.isEmpty()).to.be.true
  24. })
  25. it('should not create a range with a negative position', function () {
  26. expect(() => new Range(-1, 10)).to.throw
  27. })
  28. it('should not create a range with a negative length', function () {
  29. expect(() => new Range(0, -2)).to.throw
  30. })
  31. describe('overlaps', function () {
  32. it('same ranges should overlap', function () {
  33. const range1 = new Range(1, 3)
  34. const range2 = new Range(1, 3)
  35. expect(range1.overlaps(range2)).to.eql(true)
  36. })
  37. it('non-touching ranges should not overlap', function () {
  38. const from1to3 = new Range(1, 3)
  39. const from10to12 = new Range(10, 3)
  40. expect(from1to3.overlaps(from10to12)).to.eql(false)
  41. expect(from10to12.overlaps(from1to3)).to.eql(false)
  42. })
  43. it('touching ranges should not overlap', function () {
  44. const from1to3 = new Range(1, 3)
  45. const from4to6 = new Range(4, 3)
  46. expect(from1to3.overlaps(from4to6)).to.eql(false)
  47. expect(from4to6.overlaps(from1to3)).to.eql(false)
  48. })
  49. it('should overlap', function () {
  50. const from1to3 = new Range(1, 3)
  51. const from2to4 = new Range(2, 3)
  52. expect(from1to3.overlaps(from2to4)).to.eql(true)
  53. expect(from2to4.overlaps(from1to3)).to.eql(true)
  54. })
  55. })
  56. describe('touches', function () {
  57. it('should not touch if ranges are the same', function () {
  58. const range1 = new Range(1, 3)
  59. const range2 = new Range(1, 3)
  60. expect(range1.touches(range2)).to.eql(false)
  61. expect(range2.touches(range1)).to.eql(false)
  62. })
  63. it('should return true when ranges touch at one point', function () {
  64. const from1to3 = new Range(1, 3)
  65. const from4to5 = new Range(4, 2)
  66. expect(from1to3.touches(from4to5)).to.eql(true)
  67. expect(from4to5.touches(from1to3)).to.eql(true)
  68. })
  69. it('should return false when ranges do not touch', function () {
  70. const from1to3 = new Range(1, 3)
  71. const from5to6 = new Range(5, 2)
  72. expect(from1to3.touches(from5to6)).to.eql(false)
  73. expect(from5to6.touches(from1to3)).to.eql(false)
  74. })
  75. it('should return false when ranges overlap', function () {
  76. const from1to3 = new Range(1, 3)
  77. const from3to4 = new Range(3, 2)
  78. expect(from1to3.touches(from3to4)).to.eql(false)
  79. expect(from3to4.touches(from1to3)).to.eql(false)
  80. })
  81. })
  82. it('should check if range contains another', function () {
  83. const from0to2 = new Range(0, 3)
  84. const from4to13 = new Range(4, 10)
  85. const from4to14 = new Range(4, 11)
  86. const from4to15 = new Range(4, 12)
  87. const from5to13 = new Range(5, 9)
  88. const from5to14 = new Range(5, 10)
  89. const from5to15 = new Range(5, 11)
  90. const from0to99 = new Range(0, 100)
  91. expect(from0to2.contains(from0to2)).to.eql(true)
  92. expect(from0to2.contains(from4to13)).to.eql(false)
  93. expect(from0to2.contains(from4to14)).to.eql(false)
  94. expect(from0to2.contains(from4to15)).to.eql(false)
  95. expect(from0to2.contains(from5to13)).to.eql(false)
  96. expect(from0to2.contains(from5to14)).to.eql(false)
  97. expect(from0to2.contains(from5to15)).to.eql(false)
  98. expect(from0to2.contains(from0to99)).to.eql(false)
  99. expect(from4to13.contains(from0to2)).to.eql(false)
  100. expect(from4to13.contains(from4to13)).to.eql(true)
  101. expect(from4to13.contains(from4to14)).to.eql(false)
  102. expect(from4to13.contains(from4to15)).to.eql(false)
  103. expect(from4to13.contains(from5to13)).to.eql(true)
  104. expect(from4to13.contains(from5to14)).to.eql(false)
  105. expect(from4to13.contains(from5to15)).to.eql(false)
  106. expect(from4to13.contains(from0to99)).to.eql(false)
  107. expect(from4to14.contains(from0to2)).to.eql(false)
  108. expect(from4to14.contains(from4to13)).to.eql(true)
  109. expect(from4to14.contains(from4to14)).to.eql(true)
  110. expect(from4to14.contains(from4to15)).to.eql(false)
  111. expect(from4to14.contains(from5to13)).to.eql(true)
  112. expect(from4to14.contains(from5to14)).to.eql(true)
  113. expect(from4to14.contains(from5to15)).to.eql(false)
  114. expect(from4to14.contains(from0to99)).to.eql(false)
  115. expect(from4to15.contains(from0to2)).to.eql(false)
  116. expect(from4to15.contains(from4to13)).to.eql(true)
  117. expect(from4to15.contains(from4to14)).to.eql(true)
  118. expect(from4to15.contains(from4to15)).to.eql(true)
  119. expect(from4to15.contains(from5to13)).to.eql(true)
  120. expect(from4to15.contains(from5to14)).to.eql(true)
  121. expect(from4to15.contains(from5to15)).to.eql(true)
  122. expect(from4to15.contains(from0to99)).to.eql(false)
  123. expect(from5to13.contains(from0to2)).to.eql(false)
  124. expect(from5to13.contains(from4to13)).to.eql(false)
  125. expect(from5to13.contains(from4to14)).to.eql(false)
  126. expect(from5to13.contains(from4to15)).to.eql(false)
  127. expect(from5to13.contains(from5to13)).to.eql(true)
  128. expect(from5to13.contains(from5to14)).to.eql(false)
  129. expect(from5to13.contains(from5to15)).to.eql(false)
  130. expect(from5to13.contains(from0to99)).to.eql(false)
  131. expect(from5to14.contains(from0to2)).to.eql(false)
  132. expect(from5to14.contains(from4to13)).to.eql(false)
  133. expect(from5to14.contains(from4to14)).to.eql(false)
  134. expect(from5to14.contains(from4to15)).to.eql(false)
  135. expect(from5to14.contains(from5to13)).to.eql(true)
  136. expect(from5to14.contains(from5to14)).to.eql(true)
  137. expect(from5to14.contains(from5to15)).to.eql(false)
  138. expect(from5to14.contains(from0to99)).to.eql(false)
  139. expect(from5to15.contains(from0to2)).to.eql(false)
  140. expect(from5to15.contains(from4to13)).to.eql(false)
  141. expect(from5to15.contains(from4to14)).to.eql(false)
  142. expect(from5to15.contains(from4to15)).to.eql(false)
  143. expect(from5to15.contains(from5to13)).to.eql(true)
  144. expect(from5to15.contains(from5to14)).to.eql(true)
  145. expect(from5to15.contains(from5to15)).to.eql(true)
  146. expect(from5to15.contains(from0to99)).to.eql(false)
  147. expect(from0to99.contains(from0to2)).to.eql(true)
  148. expect(from0to99.contains(from4to13)).to.eql(true)
  149. expect(from0to99.contains(from4to14)).to.eql(true)
  150. expect(from0to99.contains(from4to15)).to.eql(true)
  151. expect(from0to99.contains(from5to13)).to.eql(true)
  152. expect(from0to99.contains(from5to14)).to.eql(true)
  153. expect(from0to99.contains(from5to15)).to.eql(true)
  154. expect(from0to99.contains(from0to99)).to.eql(true)
  155. })
  156. it('should check if range contains a cursor', function () {
  157. const from5to14 = new Range(5, 10)
  158. expect(from5to14.containsCursor(4)).to.eql(false)
  159. expect(from5to14.containsCursor(5)).to.eql(true)
  160. expect(from5to14.containsCursor(6)).to.eql(true)
  161. expect(from5to14.containsCursor(14)).to.eql(true)
  162. expect(from5to14.containsCursor(15)).to.eql(true)
  163. expect(from5to14.containsCursor(16)).to.eql(false)
  164. })
  165. describe('subtract range from another', function () {
  166. it('should not subtract', function () {
  167. const from1to5 = new Range(1, 6)
  168. const from0to1 = new Range(0, 1)
  169. const subtracted = from1to5.subtract(from0to1)
  170. expect(subtracted.start).to.eql(1)
  171. expect(subtracted.length).to.eql(6)
  172. })
  173. it('should subtract from the left', function () {
  174. const from5to19 = new Range(5, 15)
  175. const from15to24 = new Range(15, 10)
  176. const subtracted = from15to24.subtract(from5to19)
  177. expect(subtracted.start).to.eql(5)
  178. expect(subtracted.end).to.eql(10)
  179. })
  180. it('should subtract from the right', function () {
  181. const from10to24 = new Range(10, 15)
  182. const from5to19 = new Range(5, 15)
  183. const subtracted = from5to19.subtract(from10to24)
  184. expect(subtracted.start).to.eql(5)
  185. expect(subtracted.end).to.eql(10)
  186. })
  187. it('should subtract from the middle', function () {
  188. const from5to19 = new Range(5, 15)
  189. const from10to14 = new Range(10, 5)
  190. const subtracted = from5to19.subtract(from10to14)
  191. expect(subtracted.start).to.eql(5)
  192. expect(subtracted.end).to.eql(15)
  193. })
  194. it('should delete entire range', function () {
  195. const from0to99 = new Range(0, 100)
  196. const from5to19 = new Range(5, 15)
  197. const subtracted = from5to19.subtract(from0to99)
  198. expect(subtracted.start).to.eql(5)
  199. expect(subtracted.end).to.eql(5)
  200. expect(subtracted.length).to.eql(0)
  201. })
  202. it('should not subtract if ranges do not overlap', function () {
  203. const from5to14 = new Range(5, 10)
  204. const from20to29 = new Range(20, 10)
  205. const subtracted1 = from5to14.subtract(from20to29)
  206. const subtracted2 = from20to29.subtract(from5to14)
  207. expect(subtracted1.toRaw()).deep.equal(from5to14.toRaw())
  208. expect(subtracted2.toRaw()).deep.equal(from20to29.toRaw())
  209. })
  210. })
  211. describe('merge ranges', function () {
  212. it('should merge ranges overlaping at the end', function () {
  213. const from5to14 = new Range(5, 10)
  214. const from10to19 = new Range(10, 10)
  215. expect(from5to14.canMerge(from10to19)).to.eql(true)
  216. const result = from5to14.merge(from10to19)
  217. expect(result.start).to.eql(5)
  218. expect(result.end).to.eql(20)
  219. })
  220. it('should merge ranges overlaping at the start', function () {
  221. const from5to14 = new Range(5, 10)
  222. const from0to9 = new Range(0, 10)
  223. expect(from5to14.canMerge(from0to9)).to.eql(true)
  224. const result = from5to14.merge(from0to9)
  225. expect(result.start).to.eql(0)
  226. expect(result.end).to.eql(15)
  227. })
  228. it('should merge ranges if one is covered by another', function () {
  229. const from5to14 = new Range(5, 10)
  230. const from0to19 = new Range(0, 20)
  231. expect(from5to14.canMerge(from0to19)).to.eql(true)
  232. const result = from5to14.merge(from0to19)
  233. expect(result.toRaw()).deep.equal(from0to19.toRaw())
  234. })
  235. it('should produce the same length after merge', function () {
  236. const from5to14 = new Range(5, 10)
  237. const from0to19 = new Range(0, 20)
  238. expect(from0to19.canMerge(from5to14)).to.eql(true)
  239. const result = from0to19.merge(from5to14)
  240. expect(result.start).to.eql(0)
  241. expect(result.end).to.eql(20)
  242. })
  243. it('should not merge ranges if they do not overlap', function () {
  244. const from5to14 = new Range(5, 10)
  245. const from20to29 = new Range(20, 10)
  246. expect(from5to14.canMerge(from20to29)).to.eql(false)
  247. expect(from20to29.canMerge(from5to14)).to.eql(false)
  248. expect(() => from5to14.merge(from20to29)).to.throw()
  249. })
  250. })
  251. it('should check if range starts after a range', function () {
  252. const from0to4 = new Range(0, 5)
  253. const from1to5 = new Range(1, 5)
  254. const from5to9 = new Range(5, 5)
  255. const from6to10 = new Range(6, 5)
  256. const from10to14 = new Range(10, 5)
  257. expect(from0to4.startsAfter(from0to4)).to.eql(false)
  258. expect(from0to4.startsAfter(from1to5)).to.eql(false)
  259. expect(from0to4.startsAfter(from5to9)).to.eql(false)
  260. expect(from0to4.startsAfter(from6to10)).to.eql(false)
  261. expect(from0to4.startsAfter(from10to14)).to.eql(false)
  262. expect(from1to5.startsAfter(from0to4)).to.eql(false)
  263. expect(from1to5.startsAfter(from1to5)).to.eql(false)
  264. expect(from1to5.startsAfter(from5to9)).to.eql(false)
  265. expect(from1to5.startsAfter(from6to10)).to.eql(false)
  266. expect(from1to5.startsAfter(from10to14)).to.eql(false)
  267. expect(from5to9.startsAfter(from0to4)).to.eql(true)
  268. expect(from5to9.startsAfter(from1to5)).to.eql(false)
  269. expect(from5to9.startsAfter(from5to9)).to.eql(false)
  270. expect(from5to9.startsAfter(from6to10)).to.eql(false)
  271. expect(from5to9.startsAfter(from10to14)).to.eql(false)
  272. expect(from6to10.startsAfter(from0to4)).to.eql(true)
  273. expect(from6to10.startsAfter(from1to5)).to.eql(true)
  274. expect(from6to10.startsAfter(from5to9)).to.eql(false)
  275. expect(from6to10.startsAfter(from6to10)).to.eql(false)
  276. expect(from6to10.startsAfter(from10to14)).to.eql(false)
  277. expect(from10to14.startsAfter(from0to4)).to.eql(true)
  278. expect(from10to14.startsAfter(from1to5)).to.eql(true)
  279. expect(from10to14.startsAfter(from5to9)).to.eql(true)
  280. expect(from10to14.startsAfter(from6to10)).to.eql(false)
  281. expect(from10to14.startsAfter(from10to14)).to.eql(false)
  282. })
  283. it('should check if range starts after a position', function () {
  284. const from5to14 = new Range(5, 10)
  285. expect(from5to14.startIsAfter(3)).to.be.true
  286. expect(from5to14.startIsAfter(4)).to.be.true
  287. expect(from5to14.startIsAfter(5)).to.be.false
  288. expect(from5to14.startIsAfter(6)).to.be.false
  289. expect(from5to14.startIsAfter(15)).to.be.false
  290. expect(from5to14.startIsAfter(16)).to.be.false
  291. })
  292. it('should extend the range', function () {
  293. const from5to14 = new Range(5, 10)
  294. const result = from5to14.extendBy(3)
  295. expect(result.length).to.eql(13)
  296. expect(result.start).to.eql(5)
  297. expect(result.end).to.eql(18)
  298. })
  299. it('should shrink the range', function () {
  300. const from5to14 = new Range(5, 10)
  301. const result = from5to14.shrinkBy(3)
  302. expect(result.length).to.eql(7)
  303. expect(result.start).to.eql(5)
  304. expect(result.end).to.eql(12)
  305. })
  306. it('should throw if shrinking too much', function () {
  307. const from5to14 = new Range(5, 10)
  308. expect(() => from5to14.shrinkBy(11)).to.throw()
  309. })
  310. it('should move the range', function () {
  311. const from5to14 = new Range(5, 10)
  312. const result = from5to14.moveBy(3)
  313. expect(result.length).to.eql(10)
  314. expect(result.start).to.eql(8)
  315. expect(result.end).to.eql(18)
  316. })
  317. describe('splitAt', function () {
  318. it('should split at the start', function () {
  319. const range = new Range(5, 10)
  320. const [left, right] = range.splitAt(5)
  321. expect(left.isEmpty()).to.be.true
  322. expect(right.start).to.eql(5)
  323. expect(right.end).to.eql(15)
  324. })
  325. it('should not split before the start', function () {
  326. const range = new Range(5, 10)
  327. expect(() => range.splitAt(4)).to.throw()
  328. })
  329. it('should split at last cursor in range', function () {
  330. const range = new Range(5, 10)
  331. const [left, right] = range.splitAt(14)
  332. expect(left.start).to.equal(5)
  333. expect(left.end).to.equal(14)
  334. expect(right.start).to.equal(14)
  335. expect(right.end).to.equal(15)
  336. })
  337. it('should not split after the end', function () {
  338. const range = new Range(5, 10)
  339. expect(() => range.splitAt(16)).to.throw()
  340. })
  341. it('should split at end', function () {
  342. const range = new Range(5, 10)
  343. const [left, right] = range.splitAt(15)
  344. expect(left.start).to.equal(5)
  345. expect(left.end).to.equal(15)
  346. expect(right.start).to.equal(15)
  347. expect(right.end).to.equal(15)
  348. })
  349. it('should split in the middle', function () {
  350. const range = new Range(5, 10)
  351. const [left, right] = range.splitAt(10)
  352. expect(left.start).to.equal(5)
  353. expect(left.end).to.equal(10)
  354. expect(right.start).to.equal(10)
  355. expect(right.end).to.equal(15)
  356. })
  357. })
  358. describe('insertAt', function () {
  359. it('should insert at the start', function () {
  360. const range = new Range(5, 10)
  361. const [left, inserted, right] = range.insertAt(5, 3)
  362. expect(left.isEmpty()).to.be.true
  363. expect(inserted.start).to.eql(5)
  364. expect(inserted.end).to.eql(8)
  365. expect(right.start).to.eql(8)
  366. expect(right.end).to.eql(18)
  367. })
  368. it('should insert at the end', function () {
  369. const range = new Range(5, 10)
  370. const [left, inserted, right] = range.insertAt(15, 3)
  371. expect(left.start).to.eql(5)
  372. expect(left.end).to.eql(15)
  373. expect(inserted.start).to.eql(15)
  374. expect(inserted.end).to.eql(18)
  375. expect(right.isEmpty()).to.be.true
  376. })
  377. it('should insert in the middle', function () {
  378. const range = new Range(5, 10)
  379. const [left, inserted, right] = range.insertAt(10, 3)
  380. expect(left.start).to.eql(5)
  381. expect(left.end).to.eql(10)
  382. expect(inserted.start).to.eql(10)
  383. expect(inserted.end).to.eql(13)
  384. expect(right.start).to.eql(13)
  385. expect(right.end).to.eql(18)
  386. })
  387. it('should throw if cursor is out of range', function () {
  388. const range = new Range(5, 10)
  389. expect(() => range.insertAt(4, 3)).to.throw()
  390. expect(() => range.insertAt(16, 3)).to.throw()
  391. })
  392. })
  393. describe('intersect', function () {
  394. it('should handle partially overlapping ranges', function () {
  395. const range1 = new Range(5, 10)
  396. const range2 = new Range(3, 6)
  397. const intersection1 = range1.intersect(range2)
  398. expect(intersection1.pos).to.equal(5)
  399. expect(intersection1.length).to.equal(4)
  400. const intersection2 = range2.intersect(range1)
  401. expect(intersection2.pos).to.equal(5)
  402. expect(intersection2.length).to.equal(4)
  403. })
  404. it('should intersect with itself', function () {
  405. const range = new Range(5, 10)
  406. const intersection = range.intersect(range)
  407. expect(intersection.pos).to.equal(5)
  408. expect(intersection.length).to.equal(10)
  409. })
  410. it('should handle nested ranges', function () {
  411. const range1 = new Range(5, 10)
  412. const range2 = new Range(7, 2)
  413. const intersection1 = range1.intersect(range2)
  414. expect(intersection1.pos).to.equal(7)
  415. expect(intersection1.length).to.equal(2)
  416. const intersection2 = range2.intersect(range1)
  417. expect(intersection2.pos).to.equal(7)
  418. expect(intersection2.length).to.equal(2)
  419. })
  420. it('should handle disconnected ranges', function () {
  421. const range1 = new Range(5, 10)
  422. const range2 = new Range(20, 30)
  423. const intersection1 = range1.intersect(range2)
  424. expect(intersection1).to.be.null
  425. const intersection2 = range2.intersect(range1)
  426. expect(intersection2).to.be.null
  427. })
  428. })
  429. })