text: // @flow strict
  
  import { constant } from '../constants';
  import { dispatch } from '../dispatch';
  import { guard } from '../guard';
  import { number } from '../number';
  import { object } from '../object';
  import type { Decoder } from '../types';
  
  type Rectangle = {|
      type: 'rectangle',
      x: number,
      y: number,
      width: number,
      height: number,
  |};
  
  type Circle = {|
      type: 'circle',
      cx: number,
      cy: number,
      r: number,
  |};
  
  const rectangle: Decoder<Rectangle> = object({
      type: constant('rectangle'),
      x: number,
      y: number,
      width: number,
      height: number,
  });
  
  const circle: Decoder<Circle> = object({
      type: constant('circle'),
      cx: number,
      cy: number,
      r: number,
  });
  
  describe('dispatch', () => {
      const decoder = dispatch('type', { rectangle, circle });
  
      it('allows conditional decoding', () => {
          const r = { type: 'rectangle', x: 3, y: 5, width: 80, height: 100 };
          expect(guard(decoder)(r)).toEqual(r);
  
          const c = { type: 'circle', cx: 3, cy: 5, r: 7 };
          expect(decoder(c).unwrap()).toEqual(c);
      });
  
      it('invalid', () => {
          expect(() => guard(decoder)('foo')).toThrow('Must be an object');
          expect(() => guard(decoder)({})).toThrow('Missing key: "type"');
          expect(() => guard(decoder)({ type: 'blah' })).toThrow(
              /Must be one of.*rectangle.*circle/
          );
          expect(() => guard(decoder)({ type: 'rectangle', x: 1 })).toThrow(
              /Missing keys: "y", "width", "height"/
          );
      });
  });
  