|
1 | 1 | /* eslint-disable test/prefer-lowercase-title */ |
2 | 2 | import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' |
| 3 | +import { preprocessMathExpression } from '../math-notebook/math-engine/preprocess' |
3 | 4 | import { useMathEngine } from '../math-notebook/useMathEngine' |
4 | 5 |
|
5 | 6 | const TEST_CURRENCY_RATES = { |
6 | 7 | USD: 1, |
7 | 8 | EUR: 0.92, |
8 | 9 | GBP: 0.79, |
9 | 10 | CAD: 1.36, |
| 11 | + RUB: 90, |
10 | 12 | } |
11 | 13 |
|
12 | 14 | const { evaluateDocument, setCurrencyServiceState, updateCurrencyRates } |
@@ -461,6 +463,73 @@ describe('number format', () => { |
461 | 463 | }) |
462 | 464 | }) |
463 | 465 |
|
| 466 | +describe('numericValue for total', () => { |
| 467 | + it('sets numericValue for plain number', () => { |
| 468 | + const result = evalLine('42') |
| 469 | + expect(result.numericValue).toBe(42) |
| 470 | + }) |
| 471 | + |
| 472 | + it('sets numericValue for arithmetic result', () => { |
| 473 | + const result = evalLine('10 + 5') |
| 474 | + expect(result.numericValue).toBe(15) |
| 475 | + }) |
| 476 | + |
| 477 | + it('sets numericValue for number assignment', () => { |
| 478 | + const results = evalLines('x = 10') |
| 479 | + expect(results[0].numericValue).toBe(10) |
| 480 | + }) |
| 481 | + |
| 482 | + it('does not set numericValue for date', () => { |
| 483 | + const result = evalLine('now') |
| 484 | + expect(result.numericValue).toBeUndefined() |
| 485 | + }) |
| 486 | + |
| 487 | + it('does not set numericValue for date assignment', () => { |
| 488 | + const results = evalLines('x = 12.03.2025') |
| 489 | + expect(results[0].numericValue).toBeUndefined() |
| 490 | + }) |
| 491 | + |
| 492 | + it('does not set numericValue for unit result', () => { |
| 493 | + const result = evalLine('10 USD') |
| 494 | + expect(result.numericValue).toBeUndefined() |
| 495 | + }) |
| 496 | + |
| 497 | + it('does not set numericValue for unit assignment', () => { |
| 498 | + const results = evalLines('price = 10 USD') |
| 499 | + expect(results[0].numericValue).toBeUndefined() |
| 500 | + }) |
| 501 | + |
| 502 | + it('sets intValue for hex format', () => { |
| 503 | + const result = evalLine('255 in hex') |
| 504 | + expect(result.numericValue).toBe(255) |
| 505 | + }) |
| 506 | + |
| 507 | + it('sets intValue (rounded) for hex with float', () => { |
| 508 | + const result = evalLine('10.6 in hex') |
| 509 | + expect(result.numericValue).toBe(11) |
| 510 | + }) |
| 511 | + |
| 512 | + it('sets intValue for bin format', () => { |
| 513 | + const result = evalLine('255 in bin') |
| 514 | + expect(result.numericValue).toBe(255) |
| 515 | + }) |
| 516 | + |
| 517 | + it('sets intValue for oct format', () => { |
| 518 | + const result = evalLine('255 in oct') |
| 519 | + expect(result.numericValue).toBe(255) |
| 520 | + }) |
| 521 | + |
| 522 | + it('sets numericValue for sci format', () => { |
| 523 | + const result = evalLine('5300 in sci') |
| 524 | + expect(result.numericValue).toBe(5300) |
| 525 | + }) |
| 526 | + |
| 527 | + it('does not set numericValue for Infinity', () => { |
| 528 | + const result = evalLine('1/0') |
| 529 | + expect(result.numericValue).toBeUndefined() |
| 530 | + }) |
| 531 | +}) |
| 532 | + |
464 | 533 | describe('area and volume aliases', () => { |
465 | 534 | it('sq alias', () => { |
466 | 535 | const result = evalLine('20 sq cm to cm^2') |
@@ -578,6 +647,118 @@ describe('sum and total', () => { |
578 | 647 | }) |
579 | 648 | }) |
580 | 649 |
|
| 650 | +describe('adjacent digit concatenation', () => { |
| 651 | + it('concatenates space-separated digits', () => { |
| 652 | + expectValue('1 1 2', '112') |
| 653 | + }) |
| 654 | + |
| 655 | + it('works with operators before grouped digits', () => { |
| 656 | + expectValue('1 + 1 + 1 1 2', '114') |
| 657 | + }) |
| 658 | + |
| 659 | + it('concatenates two digit groups', () => { |
| 660 | + expectValue('1 0 + 2 0', '30') |
| 661 | + }) |
| 662 | + |
| 663 | + it('does not break thousands grouping', () => { |
| 664 | + expectValue('4 500', '4,500') |
| 665 | + }) |
| 666 | + |
| 667 | + it('does not break stacked units', () => { |
| 668 | + const result = evalLine('1 meter 20 cm') |
| 669 | + expect(result.type).toBe('unit') |
| 670 | + expect(result.value).toContain('1.2') |
| 671 | + }) |
| 672 | +}) |
| 673 | + |
| 674 | +describe('mixed currency and plain number', () => { |
| 675 | + it('adds plain number to currency in addition', () => { |
| 676 | + const result = evalLine('$100 + 10') |
| 677 | + expect(result.value).toContain('110') |
| 678 | + expect(result.type).toBe('unit') |
| 679 | + }) |
| 680 | + |
| 681 | + it('adds plain number to currency with multiple terms', () => { |
| 682 | + const result = evalLine('$100 + $200 + 10') |
| 683 | + expect(result.value).toContain('310') |
| 684 | + expect(result.type).toBe('unit') |
| 685 | + }) |
| 686 | + |
| 687 | + it('adds plain number before currency', () => { |
| 688 | + const result = evalLine('10 + $100') |
| 689 | + expect(result.value).toContain('110') |
| 690 | + expect(result.type).toBe('unit') |
| 691 | + }) |
| 692 | + |
| 693 | + it('subtracts plain number from currency', () => { |
| 694 | + const result = evalLine('$100 - 10') |
| 695 | + expect(result.value).toContain('90') |
| 696 | + expect(result.type).toBe('unit') |
| 697 | + }) |
| 698 | + |
| 699 | + it('does not modify multiplication with plain number', () => { |
| 700 | + const result = evalLine('$100 * 2') |
| 701 | + expect(result.value).toContain('200') |
| 702 | + expect(result.type).toBe('unit') |
| 703 | + }) |
| 704 | + |
| 705 | + it('does not modify division with plain number', () => { |
| 706 | + const result = evalLine('$100 / 4') |
| 707 | + expect(result.value).toContain('25') |
| 708 | + expect(result.type).toBe('unit') |
| 709 | + }) |
| 710 | + |
| 711 | + it('does not modify expression without currency', () => { |
| 712 | + expectValue('10 + 20', '30') |
| 713 | + }) |
| 714 | + |
| 715 | + it('works with word operator plus', () => { |
| 716 | + const result = evalLine('$100 plus 10') |
| 717 | + expect(result.value).toContain('110') |
| 718 | + expect(result.type).toBe('unit') |
| 719 | + }) |
| 720 | + |
| 721 | + it('works with word operator minus', () => { |
| 722 | + const result = evalLine('$100 minus 10') |
| 723 | + expect(result.value).toContain('90') |
| 724 | + expect(result.type).toBe('unit') |
| 725 | + }) |
| 726 | + |
| 727 | + it('does not infer currency for percentage operands', () => { |
| 728 | + expect(preprocessMathExpression('$100 + 10%')).toBe('100 USD + 10 / 100') |
| 729 | + }) |
| 730 | + |
| 731 | + it('keeps trailing conversion on the whole inferred expression', () => { |
| 732 | + const result = evalLine('10 USD + 1 in RUB') |
| 733 | + expect(result.type).toBe('unit') |
| 734 | + expect(result.value).toContain('RUB') |
| 735 | + expectNumericClose('10 USD + 1 in RUB', 990, 2) |
| 736 | + }) |
| 737 | +}) |
| 738 | + |
| 739 | +describe('mixed unit and plain number', () => { |
| 740 | + it('adds plain number to day unit', () => { |
| 741 | + const result = evalLine('10 day + 34') |
| 742 | + expect(result.type).toBe('unit') |
| 743 | + expect(result.value).toContain('day') |
| 744 | + expectNumericClose('10 day + 34', 44, 2) |
| 745 | + }) |
| 746 | + |
| 747 | + it('adds plain number before day unit', () => { |
| 748 | + const result = evalLine('34 + 10 day') |
| 749 | + expect(result.type).toBe('unit') |
| 750 | + expect(result.value).toContain('day') |
| 751 | + expectNumericClose('34 + 10 day', 44, 2) |
| 752 | + }) |
| 753 | + |
| 754 | + it('adds plain number after adjacent digit concatenation with unit', () => { |
| 755 | + const result = evalLine('1 0 day + 34') |
| 756 | + expect(result.type).toBe('unit') |
| 757 | + expect(result.value).toContain('day') |
| 758 | + expectNumericClose('1 0 day + 34', 44, 2) |
| 759 | + }) |
| 760 | +}) |
| 761 | + |
581 | 762 | describe('average and avg', () => { |
582 | 763 | it('average of lines above', () => { |
583 | 764 | const results = evalLines('10\n20\n30\naverage') |
|
0 commit comments