Home Reference Source Test

spec/match.spec.ts

  1. import 'mocha';
  2.  
  3. import { given } from 'mocha-testdata';
  4.  
  5. import { match, TinyType, TinyTypeOf } from '../src';
  6. import { IdentityMatcher, ObjectMatcher, StringMatcher } from '../src/pattern-matching';
  7. import { expect } from './expect';
  8.  
  9. /** @test {match} */
  10. describe(`::match`, () => {
  11.  
  12. /** @test {match} */
  13. describe('default rules', () => {
  14. it(`uses the default rule when no identical match is found for a string value`, () => {
  15. const result = match('four')
  16. .when('five', _ => `high five`)
  17. .when('six', _ => `got your six`)
  18. .else(n => `got ${n}`);
  19.  
  20. expect(result).to.equal('got four');
  21. });
  22.  
  23. it(`uses the default rule when no identical match is found for a numerical value`, () => {
  24. const result = match(4)
  25. .when(5, _ => `high five`)
  26. .when(6, _ => `got your six`)
  27. .else(n => `got ${n}`);
  28.  
  29. expect(result).to.equal('got 4');
  30. });
  31. });
  32.  
  33. describe('when selecting a matcher', () => {
  34. abstract class DomainEvent {
  35. constructor(public readonly timestamp: Date = new Date()) {
  36. }
  37. }
  38.  
  39. class ConcreteEvent extends DomainEvent {
  40. }
  41.  
  42. class EmaiAddress extends TinyType {
  43. constructor(public readonly value: string) {
  44. super();
  45. }
  46. }
  47.  
  48. given([
  49. { input: 5, pattern: 1, expected_matcher: IdentityMatcher },
  50. { input: Symbol('some'), pattern: Symbol('other'), expected_matcher: IdentityMatcher },
  51. { input: 'hello', pattern: 'hello', expected_matcher: StringMatcher },
  52. { input: 'hello', pattern: /^[Hh]ello/, expected_matcher: StringMatcher },
  53. { input: new EmaiAddress('user@domain.org'), pattern: new EmaiAddress('user@domain.org'), expected_matcher: ObjectMatcher },
  54. { input: new ConcreteEvent(), pattern: ConcreteEvent, expected_matcher: ObjectMatcher },
  55. { input: new ConcreteEvent(), pattern: DomainEvent, expected_matcher: ObjectMatcher },
  56. ]).
  57. it(`uses a matcher appropriate to the input`, ({input, pattern, expected_matcher}) => {
  58. expect(match(input).when(pattern, _ => _)).to.be.instanceOf(expected_matcher);
  59. });
  60. });
  61.  
  62. /**
  63. * @test {match}
  64. * @test {TinyType}
  65. * @test {TinyTypeOf}
  66. */
  67. describe('when working with TinyTypes', () => {
  68.  
  69. class AccountId extends TinyTypeOf<number>() {}
  70. abstract class Command extends TinyTypeOf<AccountId>() {}
  71. class OpenAccount extends Command {}
  72. class CloseAccount extends Command {}
  73. class SuspendAccount extends Command {}
  74.  
  75. given([
  76. { command: new OpenAccount(new AccountId(42)), expected: 'Open AccountId(value=42)' },
  77. { command: new CloseAccount(new AccountId(42)), expected: 'Close AccountId(value=42)' },
  78. { command: new SuspendAccount(new AccountId(42)), expected: 'Command: SuspendAccount(value=AccountId(value=42))' },
  79. { command: null, expected: 'Unrecognised input: null' },
  80. ]).
  81. it('matches a TinyType by type', ({ command, expected }) => {
  82. const result = match(command)
  83. .when(OpenAccount, ({ value }) => `Open ${ value }`)
  84. .when(CloseAccount, ({ value }) => `Close ${ value }`)
  85. .when(Command, _ => `Command: ${ _ }`)
  86. .else(_ => `Unrecognised input: ${_}`);
  87.  
  88. expect(result).to.equal(expected);
  89. });
  90.  
  91. given([
  92. { command: new OpenAccount(new AccountId(42)), expected: 'Open AccountId(value=42)' },
  93. { command: new CloseAccount(new AccountId(42)), expected: 'Close AccountId(value=42)' },
  94. { command: new SuspendAccount(new AccountId(42)), expected: 'Command: SuspendAccount(value=AccountId(value=42))' },
  95. { command: null, expected: 'Unrecognised input: null' },
  96. ]).
  97. it('matches a TinyType by value', ({ command, expected }) => {
  98. const result = match(command)
  99. .when(new OpenAccount(new AccountId(42)), ({ value }) => `Open ${ value }`)
  100. .when(new CloseAccount(new AccountId(42)), ({ value }) => `Close ${ value }`)
  101. .when(new SuspendAccount(new AccountId(42)), _ => `Command: ${ _ }`)
  102. .else(_ => `Unrecognised input: ${_}`);
  103.  
  104. expect(result).to.equal(expected);
  105. });
  106. });
  107. });