<commit_before>import React, { Fragment } from 'react'
import {
  Box,
  Flex,
  Container,
  Text,
  Heading,
  Button,
  LargeButton,
  Link as A,
  Card,
  Image
} from '@hackclub/design-system'
import Link from 'gatsby-link'
import Helmet from 'react-helmet'
import Nav from 'components/Nav'
import Animator from 'components/Animator'
import Module from 'components/Module'

const Base = Box.extend`
  background-color: #111;
  width: 100%;
  max-width: 100vw;
  min-height: 100vh;
  color: ${({ theme }) => theme.colors.gray[3]};
  background-image: radial-gradient(circle, #444, #444 1px, #111 1px, #111);
  background-size: 2rem 2rem;
`

const CTA = Button.extend`
  text-transform: uppercase;
`
CTA.defaultProps = {
  bg: 'teal.6',
  color: 'white',
  py: 3,
  px: 4,
  f: 2
}

const Modules = Container.extend`
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  grid-gap: ${({ theme }) => theme.space[3]}px;
  h3,
  svg {
    color: ${({ theme }) => theme.colors.white};
  }
  ${({ theme }) => theme.mediaQueries.md} {
    grid-gap: ${({ theme }) => theme.space[4]}px;
    > div {
      align-items: center;
    }
  }
`
Modules.defaultProps = {
  py: 0,
  px: 3,
  my: 3,
  mx: 'auto',
  maxWidth: 64,
  align: ['left', 'center']
}

const Internal = A.withComponent(Link).extend.attrs({ color: 'inherit' })``

const Alt = Container.withComponent(Flex).extend.attrs({
  maxWidth: 64,
  px: 3,
  flexDirection: 'column'
})`text-align: left;`
const AltBox = Box.extend.attrs({ my: 4 })`
  max-width: 36rem;
`
const AltLeft = AltBox.extend``
const AltRight = AltBox.extend.attrs({ ml: 'auto' })``

const Megaline = Heading.h1.extend.attrs({
  f: [6, 7],
  color: 'white'
})`line-height: 1.125;`
const Headline = Heading.h2.extend.attrs({
  f: [5, 6],
  mb: 3,
  color: 'snow',
  bold: true
})`line-height: 1.125;`
const subhline = { f: [3, 4], style: { lineHeight: '1.375' } }

const Lead = Container.withComponent(Text)
Lead.defaultProps = { f: 3, mx: 'auto' }

const Banner = Container.extend``
Banner.defaultProps = {
  maxWidth: 48,
  mt: 5,
  mb: [3, 4],
  mx: 'auto',
  px: 3,
  align: ['left', 'center']
}

const Join = Card.withComponent(Container).extend`
  display: grid;
  grid-gap: ${({ theme }) => theme.space[3]}px;
  align-items: flex-start;
  ${({ theme }) => theme.mediaQueries.md} {
    grid-template-columns: 32rem auto;
  }
`

const Breakdown = Box.extend`
  div {
    width: 100%;
    display: block;
    text-align: left !important;
  }
  span:before {
    content: '$';
    font-size: ${({ theme }) => theme.fontSizes[4]}px;
    margin-left: -12px;
    vertical-align: super;
  }
  p {
    color: ${({ theme }) => theme.colors.red[1]};
  }
`

const title = 'Hack Club Bank – The Bank For Student Hackers'
const desc =
  'Get a bank account for your high school coding event or hackathon with the backing of a 501(c)(3) non-profit. Student organizers can invoice sponsors, issue physical debit cards, and get access to their event’s financials through a real-time dashboard.'
const img = 'https://hackclub.com/bank-banner.png'

export default () => (
  <Base align="center">
    <Helmet
      title={title}
      meta={[
        { name: 'description', content: desc },
        { name: 'twitter:title', content: title },
        { name: 'twitter:description', content: desc },
        { name: 'twitter:image', content: img },
        { property: 'og:title', content: title },
        { property: 'og:description', content: desc },
        { property: 'og:image', content: img },
        { property: 'og:url', content: 'https://hackclub.com/bank' }
      ]}
    />
    <Nav color="smoke" bgColor="rgba(40, 40, 40, 0.96)" />
    <Animator
      is={Box}
      data={{
        opacity: [1, 0.75],
        transform: [{ translateY: '0px' }, { translateY: '-64px' }]
      }}
    >
      <Megaline pt={[5, 6]}>The bank for student hackers.</Megaline>
      <Lead px={3} maxWidth={48} my={[3, 4]}>
        Hack Club Bank is the best place for high school hackers to store money
        for hackathons. Student organizers can invoice sponsors, issue physical
        debit cards, and get access to their event’s financials through a
        real-time dashboard all with the benefits of the backing of a 501(c)(3)
        nonprofit.
      </Lead>
    </Animator>
    <Flex justify="center" mb={[3, 4]}>
      <CTA
        href="https://medium.com/hackclub/a-bank-for-student-hackers-e5d894ea5375"
        target="_blank"
        scale
        chevronRight
      >
        Read the announcement
      </CTA>
    </Flex>
    <Banner>
      <Headline>Finances, done right.</Headline>
      <Lead maxWidth={36}>
        No waiting days for an email reply about your balance. Everything is
        immediately available and easy to see.
      </Lead>
    </Banner>
    <Modules>
      <Module
        icon="account_balance"
        name="Bank account"
        body="Get a 501(c)(3) non-profit bank account (contributions will be tax-deductible)."
      />
      <Module
        icon="history"
        name="Balance + history"
        body="Check real-time account balance and transaction history any time."
      />
      <Module
        icon="receipt"
        name="Manage your finances"
        body="Add notes to transactions, export data, issue reimbursements. Easy."
      />
    </Modules>
    <Container maxWidth={70} my={[4, 3]}>
      <Image w={1} src="/bank-screenshot.png" />
    </Container>
    <Banner mt={0}>
      <Headline>A powerful toolbox for organizing your event.</Headline>
      <Lead maxWidth={32}>
        We’ve got all the tools to start getting your event ready, from domain
        email to legal forms.
      </Lead>
    </Banner>
    <Modules>
      <Module
        icon="description"
        name="Pre-written forms"
        body="Download free consent and photo release forms for your event. No lawyers needed."
      />
      <Module
        icon="credit_card"
        name="Debit cards"
        body="Issue physical debit cards to all your team members—no need for reimbursements."
      />
      <Module
        icon="cloud"
        name="G Suite"
        body="Get free G Suite + email addresses (like megan@hackchicago.io) for everyone."
      />
    </Modules>
    <Banner>
      <Headline>We’re here to help out.</Headline>
      <Lead maxWidth={36}>
        Planning your event is enough work. Let us answer questions and do the
        background work.
      </Lead>
    </Banner>
    <Modules>
      <Module
        icon="local_atm"
        name="Taxes + accounting"
        body="We’ll handle end-of-year taxes and accounting in the background."
      />
      <Module
        icon="live_help"
        name="Support anytime"
        body="Questions? We’ll never leave you in the dark. Best-effort 12hr response time."
      />
      <Module
        icon="forum"
        name="Community"
        body="Talk to our community of experienced event organizers anytime."
      />
    </Modules>
    <Container maxWidth={48} pt={4} pb={[5, 6]} px={3}>
      <Join align="left" bg="black" p={[3, 4]}>
        <Container maxWidth={32} mx={0}>
          <Heading.h2 {...subhline} color="white">
            Ready to join Hack Club Bank?
          </Heading.h2>
          <Text>
            You can join immediately with an invitation from an existing Bank
            user or a member of the Hack Club community. Otherwise, tell us
            about your event and we’ll get back to you within two weeks.
          </Text>
        </Container>
        <CTA
          href="https://goo.gl/forms/1UzFR4zkljL7dHQ32"
          target="_blank"
          scale
          chevronRight
        >
          Apply
        </CTA>
      </Join>
      <Lead maxWidth={32} color="slate" f={1} mt={3}>
        Hack Club does not directly provide banking services. Banking services
        provided by Silicon Valley Bank, an FDIC-certified institution.
      </Lead>
    </Container>
  </Base>
)
<commit_msg>Remove animation from /bank header<commit_after>import React, { Fragment } from 'react'
import {
  Box,
  Flex,
  Container,
  Text,
  Heading,
  Button,
  LargeButton,
  Link as A,
  Card,
  Image
} from '@hackclub/design-system'
import Link from 'gatsby-link'
import Helmet from 'react-helmet'
import Nav from 'components/Nav'
import Module from 'components/Module'

const Base = Box.extend`
  background-color: #111;
  width: 100%;
  max-width: 100vw;
  min-height: 100vh;
  color: ${({ theme }) => theme.colors.gray[3]};
  background-image: radial-gradient(circle, #444, #444 1px, #111 1px, #111);
  background-size: 2rem 2rem;
`

const CTA = Button.extend`
  text-transform: uppercase;
`
CTA.defaultProps = {
  bg: 'teal.6',
  color: 'white',
  py: 3,
  px: 4,
  f: 2
}

const Modules = Container.extend`
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  grid-gap: ${({ theme }) => theme.space[3]}px;
  h3,
  svg {
    color: ${({ theme }) => theme.colors.white};
  }
  ${({ theme }) => theme.mediaQueries.md} {
    grid-gap: ${({ theme }) => theme.space[4]}px;
    > div {
      align-items: center;
    }
  }
`
Modules.defaultProps = {
  py: 0,
  px: 3,
  my: 3,
  mx: 'auto',
  maxWidth: 64,
  align: ['left', 'center']
}

const Internal = A.withComponent(Link).extend.attrs({ color: 'inherit' })``

const Alt = Container.withComponent(Flex).extend.attrs({
  maxWidth: 64,
  px: 3,
  flexDirection: 'column'
})`text-align: left;`
const AltBox = Box.extend.attrs({ my: 4 })`
  max-width: 36rem;
`
const AltLeft = AltBox.extend``
const AltRight = AltBox.extend.attrs({ ml: 'auto' })``

const Megaline = Heading.h1.extend.attrs({
  f: [6, 7],
  color: 'white'
})`line-height: 1.125;`
const Headline = Heading.h2.extend.attrs({
  f: [5, 6],
  mb: 3,
  color: 'snow',
  bold: true
})`line-height: 1.125;`
const subhline = { f: [3, 4], style: { lineHeight: '1.375' } }

const Lead = Container.withComponent(Text)
Lead.defaultProps = { f: 3, mx: 'auto' }

const Banner = Container.extend``
Banner.defaultProps = {
  maxWidth: 48,
  mt: 5,
  mb: [3, 4],
  mx: 'auto',
  px: 3,
  align: ['left', 'center']
}

const Join = Card.withComponent(Container).extend`
  display: grid;
  grid-gap: ${({ theme }) => theme.space[3]}px;
  align-items: flex-start;
  ${({ theme }) => theme.mediaQueries.md} {
    grid-template-columns: 32rem auto;
  }
`

const Breakdown = Box.extend`
  div {
    width: 100%;
    display: block;
    text-align: left !important;
  }
  span:before {
    content: '$';
    font-size: ${({ theme }) => theme.fontSizes[4]}px;
    margin-left: -12px;
    vertical-align: super;
  }
  p {
    color: ${({ theme }) => theme.colors.red[1]};
  }
`

const title = 'Hack Club Bank – The Bank For Student Hackers'
const desc =
  'Get a bank account for your high school coding event or hackathon with the backing of a 501(c)(3) non-profit. Student organizers can invoice sponsors, issue physical debit cards, and get access to their event’s financials through a real-time dashboard.'
const img = 'https://hackclub.com/bank-banner.png'

export default () => (
  <Base align="center">
    <Helmet
      title={title}
      meta={[
        { name: 'description', content: desc },
        { name: 'twitter:title', content: title },
        { name: 'twitter:description', content: desc },
        { name: 'twitter:image', content: img },
        { property: 'og:title', content: title },
        { property: 'og:description', content: desc },
        { property: 'og:image', content: img },
        { property: 'og:url', content: 'https://hackclub.com/bank' }
      ]}
    />
    <Nav color="smoke" bgColor="rgba(40, 40, 40, 0.96)" />
    <Box>
      <Megaline pt={[5, 6]}>The bank for student hackers.</Megaline>
      <Lead px={3} maxWidth={48} my={[3, 4]}>
        Hack Club Bank is the best place for high school hackers to store money
        for hackathons. Student organizers can invoice sponsors, issue physical
        debit cards, and get access to their event’s financials through a
        real-time dashboard all with the benefits of the backing of a 501(c)(3)
        nonprofit.
      </Lead>
    </Box>
    <Flex justify="center" mb={[3, 4]}>
      <CTA
        href="https://medium.com/hackclub/a-bank-for-student-hackers-e5d894ea5375"
        target="_blank"
        scale
        chevronRight
      >
        Read the announcement
      </CTA>
    </Flex>
    <Banner>
      <Headline>Finances, done right.</Headline>
      <Lead maxWidth={36}>
        No waiting days for an email reply about your balance. Everything is
        immediately available and easy to see.
      </Lead>
    </Banner>
    <Modules>
      <Module
        icon="account_balance"
        name="Bank account"
        body="Get a 501(c)(3) non-profit bank account (contributions will be tax-deductible)."
      />
      <Module
        icon="history"
        name="Balance + history"
        body="Check real-time account balance and transaction history any time."
      />
      <Module
        icon="receipt"
        name="Manage your finances"
        body="Add notes to transactions, export data, issue reimbursements. Easy."
      />
    </Modules>
    <Container maxWidth={70} my={[4, 3]}>
      <Image w={1} src="/bank-screenshot.png" />
    </Container>
    <Banner mt={0}>
      <Headline>A powerful toolbox for organizing your event.</Headline>
      <Lead maxWidth={32}>
        We’ve got all the tools to start getting your event ready, from domain
        email to legal forms.
      </Lead>
    </Banner>
    <Modules>
      <Module
        icon="description"
        name="Pre-written forms"
        body="Download free consent and photo release forms for your event. No lawyers needed."
      />
      <Module
        icon="credit_card"
        name="Debit cards"
        body="Issue physical debit cards to all your team members—no need for reimbursements."
      />
      <Module
        icon="cloud"
        name="G Suite"
        body="Get free G Suite + email addresses (like megan@hackchicago.io) for everyone."
      />
    </Modules>
    <Banner>
      <Headline>We’re here to help out.</Headline>
      <Lead maxWidth={36}>
        Planning your event is enough work. Let us answer questions and do the
        background work.
      </Lead>
    </Banner>
    <Modules>
      <Module
        icon="local_atm"
        name="Taxes + accounting"
        body="We’ll handle end-of-year taxes and accounting in the background."
      />
      <Module
        icon="live_help"
        name="Support anytime"
        body="Questions? We’ll never leave you in the dark. Best-effort 12hr response time."
      />
      <Module
        icon="forum"
        name="Community"
        body="Talk to our community of experienced event organizers anytime."
      />
    </Modules>
    <Container maxWidth={48} pt={4} pb={[5, 6]} px={3}>
      <Join align="left" bg="black" p={[3, 4]}>
        <Container maxWidth={32} mx={0}>
          <Heading.h2 {...subhline} color="white">
            Ready to join Hack Club Bank?
          </Heading.h2>
          <Text>
            You can join immediately with an invitation from an existing Bank
            user or a member of the Hack Club community. Otherwise, tell us
            about your event and we’ll get back to you within two weeks.
          </Text>
        </Container>
        <CTA
          href="https://goo.gl/forms/1UzFR4zkljL7dHQ32"
          target="_blank"
          scale
          chevronRight
        >
          Apply
        </CTA>
      </Join>
      <Lead maxWidth={32} color="slate" f={1} mt={3}>
        Hack Club does not directly provide banking services. Banking services
        provided by Silicon Valley Bank, an FDIC-certified institution.
      </Lead>
    </Container>
  </Base>
)
<|endoftext|>


<commit_before>
var address = 'https://api.github.com/repos/Coolnesss/lapio-galleria/contents/profiles'

$.get(address, function(data) {
  data.forEach(function(entry) {
    $.getJSON(entry.download_url, function(data) {
      $("#cards").append(`

${data.name} (${data.ircnick})

              ${data.description}

                Visit Homepage

`
      );
    })
  })
})
<commit_msg>Add gradient on top of background image<commit_after>
var address = 'https://api.github.com/repos/Coolnesss/lapio-galleria/contents/profiles'

$.get(address, function(data) {
  data.forEach(function(entry) {
    $.getJSON(entry.download_url, function(data) {
      $("#cards").append(`

${data.name} (${data.ircnick})

              ${data.description}

                Visit Homepage

`
      );
    })
  })
})
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import classnames from 'classnames'
//
// import _ from './utils'

const defaultButton = props => (
  <button type="button" {...props} className="-btn">
    {props.children}
  </button>
)

export default class ReactTablePagination extends Component {
  constructor (props) {
    super()

    this.getSafePage = this.getSafePage.bind(this)
    this.changePage = this.changePage.bind(this)
    this.applyPage = this.applyPage.bind(this)

    this.state = {
      page: props.page,
    }
  }

  componentWillReceiveProps (nextProps) {
    this.setState({ page: nextProps.page })
  }

  getSafePage (page) {
    if (isNaN(page)) {
      page = this.props.page
    }
    return Math.min(Math.max(page, 0), this.props.pages - 1)
  }

  changePage (page) {
    page = this.getSafePage(page)
    this.setState({ page })
    if (this.props.page !== page) {
      this.props.onPageChange(page)
    }
  }

  applyPage (e) {
    if (e) { e.preventDefault() }
    const page = this.state.page
    this.changePage(page === '' ? this.props.page : page)
  }

  render () {
    const {
      // Computed
      pages,
      // Props
      page,
      showPageSizeOptions,
      pageSizeOptions,
      pageSize,
      showPageJump,
      canPrevious,
      canNext,
      onPageSizeChange,
      className,
      PreviousComponent = defaultButton,
      NextComponent = defaultButton,
    } = this.props

    return (

          <PreviousComponent
            onClick={() => {
              if (!canPrevious) return
              this.changePage(page - 1)
            }}
            disabled={!canPrevious}
          >
            {this.props.previousText}
          </PreviousComponent>

            {this.props.pageText}{' '}
            {showPageJump
              ?

                <input
                  type={this.state.page === '' ? 'text' : 'number'}
                  onChange={e => {
                    const val = e.target.value
                    const page = val - 1
                    if (val === '') {
                      return this.setState({ page: val })
                    }
                    this.setState({ page: this.getSafePage(page) })
                  }}
                  value={this.state.page === '' ? '' : this.state.page + 1}
                  onBlur={this.applyPage}
                  onKeyPress={e => {
                    if (e.which === 13 || e.keyCode === 13) {
                      this.applyPage()
                    }
                  }}
                />

              :
                {page + 1}
              }{' '}
            {this.props.ofText}{' '}
            {pages || 1}

          {showPageSizeOptions &&

              <select
                onChange={e => onPageSizeChange(Number(e.target.value))}
                value={pageSize}
              >
                {pageSizeOptions.map((option, i) => (
                  // eslint-disable-next-line react/no-array-index-key
                  <option key={i} value={option}>
                    {option} {this.props.rowsText}
                  </option>
                ))}
              </select>
            }

          <NextComponent
            onClick={() => {
              if (!canNext) return
              this.changePage(page + 1)
            }}
            disabled={!canNext}
          >
            {this.props.nextText}
          </NextComponent>

    )
  }
}
<commit_msg>Fix style prop not being properly used in ReactTablePagination component (#785)<commit_after>import React, { Component } from 'react'
import classnames from 'classnames'
//
// import _ from './utils'

const defaultButton = props => (
  <button type="button" {...props} className="-btn">
    {props.children}
  </button>
)

export default class ReactTablePagination extends Component {
  constructor (props) {
    super()

    this.getSafePage = this.getSafePage.bind(this)
    this.changePage = this.changePage.bind(this)
    this.applyPage = this.applyPage.bind(this)

    this.state = {
      page: props.page,
    }
  }

  componentWillReceiveProps (nextProps) {
    this.setState({ page: nextProps.page })
  }

  getSafePage (page) {
    if (isNaN(page)) {
      page = this.props.page
    }
    return Math.min(Math.max(page, 0), this.props.pages - 1)
  }

  changePage (page) {
    page = this.getSafePage(page)
    this.setState({ page })
    if (this.props.page !== page) {
      this.props.onPageChange(page)
    }
  }

  applyPage (e) {
    if (e) { e.preventDefault() }
    const page = this.state.page
    this.changePage(page === '' ? this.props.page : page)
  }

  render () {
    const {
      // Computed
      pages,
      // Props
      page,
      showPageSizeOptions,
      pageSizeOptions,
      pageSize,
      showPageJump,
      canPrevious,
      canNext,
      onPageSizeChange,
      className,
      PreviousComponent = defaultButton,
      NextComponent = defaultButton,
    } = this.props

    return (

          <PreviousComponent
            onClick={() => {
              if (!canPrevious) return
              this.changePage(page - 1)
            }}
            disabled={!canPrevious}
          >
            {this.props.previousText}
          </PreviousComponent>

            {this.props.pageText}{' '}
            {showPageJump
              ?

                <input
                  type={this.state.page === '' ? 'text' : 'number'}
                  onChange={e => {
                    const val = e.target.value
                    const page = val - 1
                    if (val === '') {
                      return this.setState({ page: val })
                    }
                    this.setState({ page: this.getSafePage(page) })
                  }}
                  value={this.state.page === '' ? '' : this.state.page + 1}
                  onBlur={this.applyPage}
                  onKeyPress={e => {
                    if (e.which === 13 || e.keyCode === 13) {
                      this.applyPage()
                    }
                  }}
                />

              :
                {page + 1}
              }{' '}
            {this.props.ofText}{' '}
            {pages || 1}

          {showPageSizeOptions &&

              <select
                onChange={e => onPageSizeChange(Number(e.target.value))}
                value={pageSize}
              >
                {pageSizeOptions.map((option, i) => (
                  // eslint-disable-next-line react/no-array-index-key
                  <option key={i} value={option}>
                    {option} {this.props.rowsText}
                  </option>
                ))}
              </select>
            }

          <NextComponent
            onClick={() => {
              if (!canNext) return
              this.changePage(page + 1)
            }}
            disabled={!canNext}
          >
            {this.props.nextText}
          </NextComponent>

    )
  }
}
<|endoftext|>


<commit_before>function main() {
    $('#tabs').tabs();
    google.load('visualization', '1', {packages: ['geochart']});
    google.setOnLoadCallback(googleReady);
    var commodities_select=[];
    dojo.ready(chosenDojo);
    //Management of the selection
    $('select').on('change', function(event) {
    var select_object = dojo.byId('select');
    var select_div = dojo.byId('msg');
    var selected_values = [];
    for (x=0;x<=select_object.length;x++) {
        if (select_object[x] && select_object[x].selected) {
            selected_values.push(select_object[x].value);
        }
    }
     select_div.innerHTML = 'Selected value = ' + selected_values;
     console.log(selected_values)
    });
}

//Function to launch the googleAPI
function googleReady() {
    init_import_export();
    init_hscodes();
    worldMap();
    usaMap();
}

//Function to configure options of chosen-dojo commodities selector
function chosenDojo() {
        dojo.query(".chzn-select").chosen();
        dojo.query(".chzn-select-deselect").chosen({allow_single_deselect:true});
        dojo.query(".chzn-select-batch").chosen({batch_select:true});
    }

$(main);
<commit_msg>Trim trailing whitespace, add missing semicolon<commit_after>function main() {
    $('#tabs').tabs();
    google.load('visualization', '1', {packages: ['geochart']});
    google.setOnLoadCallback(googleReady);
    var commodities_select=[];
    dojo.ready(chosenDojo);
    //Management of the selection
    $('select').on('change', function(event) {
    var select_object = dojo.byId('select');
    var select_div = dojo.byId('msg');
    var selected_values = [];
    for (var x=0; x<=select_object.length; x++) {
        if (select_object[x] && select_object[x].selected) {
            selected_values.push(select_object[x].value);
        }
    }
     select_div.innerHTML = 'Selected value = ' + selected_values;
     console.log(selected_values);
    });
}

//Function to launch the googleAPI
function googleReady() {
    init_import_export();
    init_hscodes();
    worldMap();
    usaMap();
}

//Function to configure options of chosen-dojo commodities selector
function chosenDojo() {
        dojo.query(".chzn-select").chosen();
        dojo.query(".chzn-select-deselect").chosen({allow_single_deselect:true});
        dojo.query(".chzn-select-batch").chosen({batch_select:true});
    }

$(main);
<|endoftext|>


<commit_before>
describe('update()', function () {

	// dynalite: "ADD action is not supported for the type L", UpdateExpression
	it('.update( existing_item )', function(done) {
		// insert
		DynamoDB
			.table($tableName)
			.insert_or_replace({
				hash: 'test-update',
				range:1,
				old_number: 1,
				//old_array: [1,2,3],
				string: 'aaa',
				'ignore': 'me',
				'delete': 'me'
			}, function(err) {
				if (err)
					throw err

				DynamoDB
					.table($tableName)
					.where('hash').eq('test-update')
					.where('range').eq(1)
					.return(DynamoDB.ALL_NEW)
					.update({
						gsi_range: 'b',
						string: 'newstring',
						boolean: false,
						old_number: DynamoDB.add(9),
						null: null,
						//old_array: DynamoDB.add([ 1, 'a', null, { k1: 'v1', k2: 'v2', k3: 'v3' }, [] ]),
						object: { key1: 'value1', key2: 22 },
						delete: DynamoDB.del()
					}, function(err, data) {
						if (err)
							throw err

						assert.deepEqual(data, {
							hash: 'test-update',
							range: 1,
							old_number: 10,
							//old_array: [ 1,2,3, 1, 'a', null, { k3: 'v3', k1: 'v1', k2: 'v2' }, [] ],
							string: 'newstring',
							boolean: false,
							ignore: 'me',

							null: null,
							gsi_range: 'b',
							object: { key2: 22, key1: 'value1' },
						})
						done()
					})
			})
	})

	it('.return(DynamoDB.UPDATED_OLD).update( existing_item )', function(done) {

		DynamoDB
			.table($tableName)
			//.on('beforeRequest', function(op, payload) {
			//	console.log(op, JSON.stringify(payload,null,"\t"))
			//})
			.insert_or_replace({
				hash: 'test-updated-old',
				range: 1,

				number: 10,
				number2: 10,
				boolean: true,
			}, function(err) {
				if (err) throw err

				DynamoDB
					.table($tableName)
					.where('hash').eq('test-updated-old')
					.where('range').eq(1)
					.return(DynamoDB.UPDATED_OLD)
					//.on('beforeRequest', function(op, payload) {
					//	console.log(op, JSON.stringify(payload,null,"\t"))
					//})
					.update({
						number: DynamoDB.add(20),
						number2: 30,
						boolean: false,
					}, function(err, data ) {

						if (err) throw err
						assert.deepEqual(data, { number: 10, number2: 10, boolean: true })
						done()
					})
			})
	})

	it('.update() - test new Set( <ARRAY_OF_NUMBERS> )', function(done) {
		DynamoDB
			.table($tableName)
			.where('hash').eq('test-updated-old')
			.where('range').eq(1)
			.update({
				set: new Set([ 111, 222, 333 ]),
			}, function(err, data) {
				if (err)
					throw err

				DynamoDB
					.table($tableName)
					.where('hash').eq('test-updated-old')
					.where('range').eq(1)
					.get(function(err, item, raw ) {
						if (err)
							throw err

						assert.deepEqual(raw.Item.set.NS, [ 111, 222, 333 ], {strict: true })
						done()
					})
			})
	})

	it('.update() - test new Set( <ARRAY_OF_STRINGS> )', function(done) {
		DynamoDB
			.table($tableName)
			.where('hash').eq('test-updated-old')
			.where('range').eq(1)
			.update({
				set: new Set([ 'aaa', 'bbb', 'ccc' ]),
			}, function(err, data ) {
				if (err)
					throw err

				DynamoDB
					.table($tableName)
					.where('hash').eq('test-updated-old')
					.where('range').eq(1)
					.get(function(err, item, raw ) {
						if (err)
							throw err

						assert.deepEqual(raw.Item.set.SS, [ 'aaa', 'bbb', 'ccc'  ], {strict: true })
						done()
					})
			})
	})

	it('.update() - test new Set( <MIXED> )', function(done) {
		DynamoDB
			.table($tableName)
			.where('hash').eq('test-updated-old')
			.where('range').eq(1)
			.update({
				set1: new Set(),
				set2: new Set(['a', 1, {} ]),
			}, function(err, data ) {
				if (err)
					throw err

				DynamoDB
					.table($tableName)
					.where('hash').eq('test-updated-old')
					.where('range').eq(1)
					.get(function(err, item, raw ) {
						if (err)
							throw err

						//console.log(JSON.stringify(raw, null, "\t"))
						assert.deepEqual(raw.Item.set1.L, [], {strict: true })
						assert.deepEqual(raw.Item.set2.L, [ { "S": "a" }, { "N": "1" }, { "M": {} }  ], {strict: true })

						done()
					})
			})
	})

	it('.update().then()', function(done) {
		DynamoDB
			.table($tableName)
			.return(DynamoDB.UPDATED_OLD)
			.where('hash').eq('test-updated-old')
			.where('range').eq(1)
			.update({
				number: 1,
			})
			.then(function(data) {
				done()
			})
	})
	it('.update() - unhandled', function(done) {
		DynamoDB
			.table($tableName)
			.where('hash').eq(1)
			.where('range_unexistent').eq(1)
			.update({})
		setTimeout(function() {
			done()
		},5000)
	})
	it('.update().catch()', function(done) {
		DynamoDB
			.table($tableName)
			.where('hash').eq(1)
			.where('range_unexistent').eq(1)
			.update({})
			.catch(function(err) {
				done()
			})
	})

	it('.update() - add() to List, StringSet, NumberSet', function(done) {
		async.waterfall([

			function(cb) {
				DynamoDB
					.table($tableName)
					.insert_or_replace({
						hash: 'test-updated-ss-add',
						range: 1,
						arr: ['x','y'],
						//obj: {number: 1},
						ss: DynamoDB.SS( ['bbb','ccc'] ),
						ns: DynamoDB.NS( [ 33,22] ),
					}, function(err) {
						if (err) throw err
						cb()
					})
			},

			function(cb) {
				DynamoDB
					.table($tableName)
					.where('hash').eq('test-updated-ss-add')
					.where('range').eq(1)
					.update({
						arr: DynamoDB.add( ['x','y', false, null, {}] ),
						//obj: DynamoDB.add( { color: 'blue'} ),
						ss:  DynamoDB.add( DynamoDB.SS(['aaa','ddd']) ),
						ns:  DynamoDB.add( DynamoDB.NS([11,44]) ),

					}, function(err, data ) {
						if (err) throw err

						cb()
					})
			},

		],function(err) {
				DynamoDB
					.table($tableName)
					.where('hash').eq('test-updated-ss-add')
					.where('range').eq(1)
					//.return(DynamoDB.UPDATED_OLD)
					//.on('beforeRequest', function(op, payload) {
					//	console.log(op, JSON.stringify(payload,null,"\t"))
					//})
					.get( function(err, data ) {
						if (err) throw err

						assert.deepEqual(data.arr, [ 'x', 'y', 'x', 'y', false, null, {} ] )
						assert.deepEqual(data.ss, [ 'bbb', 'ccc', 'aaa', 'ddd' ] )
						assert.deepEqual(data.ns.sort(function(a,b) { return a > b ? 1 : -1 }), [ 11, 22, 33, 44 ] )

						done()
					})
		})
	})

	it('.update() - del() from StringSet and NumberSet', function(done) {
		async.waterfall([

			function(cb) {
				DynamoDB
					.table($tableName)
					.insert_or_replace({
						hash: 'test-updated-ss-del',
						range: 1,
						//arr: ['x','y'],
						ss: DynamoDB.SS( ['bbb','ccc'] ),
						ns: DynamoDB.NS( [ 33,22] ),
					}, function(err) {
						if (err) throw err
						cb()
					})
			},

			function(cb) {
				DynamoDB
					.table($tableName)
					.where('hash').eq('test-updated-ss-del')
					.where('range').eq(1)
					.update({

						ss:  DynamoDB.del( DynamoDB.SS(['bbb']) ),
						ns:  DynamoDB.del( DynamoDB.NS([22]) ),

					}, function(err, data ) {
						if (err) throw err

						cb()
					})
			},

		],function(err) {
				DynamoDB
					.table($tableName)
					.where('hash').eq('test-updated-ss-del')
					.where('range').eq(1)
					//.return(DynamoDB.UPDATED_OLD)
					//.on('beforeRequest', function(op, payload) {
					//	console.log(op, JSON.stringify(payload,null,"\t"))
					//})
					.get( function(err, data ) {
						if (err) throw err

						assert.deepEqual(data.ss, [ 'ccc' ] )
						assert.deepEqual(data.ns, [ 33 ] )

						done()
					})
		})
	})

	it('cleanup...', function(done) {
		DynamoDB
			.table($tableName)
			.scan(function(err, data) {
				if (err)
					throw err

				async.each(data, function(item,cb) {
					DynamoDB.table($tableName).where('hash').eq(item.hash).where('range').eq(item.range).delete(function(err) { cb(err) })
				}, function(err) {
					if (err)
						throw err

					done()
				})
			})
	})
})
<commit_msg>update() test empty string<commit_after>
describe('update()', function () {

	// dynalite: "ADD action is not supported for the type L", UpdateExpression
	it('.update( existing_item )', function(done) {
		// insert
		DynamoDB
			.table($tableName)
			.insert_or_replace({
				hash: 'test-update',
				range:1,
				old_number: 1,
				//old_array: [1,2,3],
				string: 'aaa',
				'ignore': 'me',
				'delete': 'me'
			}, function(err) {
				if (err)
					throw err

				DynamoDB
					.table($tableName)
					.where('hash').eq('test-update')
					.where('range').eq(1)
					.return(DynamoDB.ALL_NEW)
					.update({
						gsi_range: 'b',
						string: 'newstring',
						boolean: false,
						old_number: DynamoDB.add(9),
						null: null,
						//old_array: DynamoDB.add([ 1, 'a', null, { k1: 'v1', k2: 'v2', k3: 'v3' }, [] ]),
						object: { key1: 'value1', key2: 22 },
						delete: DynamoDB.del()
					}, function(err, data) {
						if (err)
							throw err

						assert.deepEqual(data, {
							hash: 'test-update',
							range: 1,
							old_number: 10,
							//old_array: [ 1,2,3, 1, 'a', null, { k3: 'v3', k1: 'v1', k2: 'v2' }, [] ],
							string: 'newstring',
							boolean: false,
							ignore: 'me',

							null: null,
							gsi_range: 'b',
							object: { key2: 22, key1: 'value1' },
						})
						done()
					})
			})
	})

	it('.return(DynamoDB.UPDATED_OLD).update( existing_item )', function(done) {

		DynamoDB
			.table($tableName)
			//.on('beforeRequest', function(op, payload) {
			//	console.log(op, JSON.stringify(payload,null,"\t"))
			//})
			.insert_or_replace({
				hash: 'test-updated-old',
				range: 1,

				number: 10,
				number2: 10,
				boolean: true,
			}, function(err) {
				if (err) throw err

				DynamoDB
					.table($tableName)
					.where('hash').eq('test-updated-old')
					.where('range').eq(1)
					.return(DynamoDB.UPDATED_OLD)
					//.on('beforeRequest', function(op, payload) {
					//	console.log(op, JSON.stringify(payload,null,"\t"))
					//})
					.update({
						number: DynamoDB.add(20),
						number2: 30,
						boolean: false,
					}, function(err, data ) {

						if (err) throw err
						assert.deepEqual(data, { number: 10, number2: 10, boolean: true })
						done()
					})
			})
	})

	it('.update() - test new Set( <ARRAY_OF_NUMBERS> )', function(done) {
		DynamoDB
			.table($tableName)
			.where('hash').eq('test-updated-old')
			.where('range').eq(1)
			.update({
				set: new Set([ 111, 222, 333 ]),
			}, function(err, data) {
				if (err)
					throw err

				DynamoDB
					.table($tableName)
					.where('hash').eq('test-updated-old')
					.where('range').eq(1)
					.get(function(err, item, raw ) {
						if (err)
							throw err

						assert.deepEqual(raw.Item.set.NS, [ 111, 222, 333 ], {strict: true })
						done()
					})
			})
	})

	it('.update() - test new Set( <ARRAY_OF_STRINGS> )', function(done) {
		DynamoDB
			.table($tableName)
			.where('hash').eq('test-updated-old')
			.where('range').eq(1)
			.update({
				set: new Set([ 'aaa', 'bbb', 'ccc' ]),
			}, function(err, data ) {
				if (err)
					throw err

				DynamoDB
					.table($tableName)
					.where('hash').eq('test-updated-old')
					.where('range').eq(1)
					.get(function(err, item, raw ) {
						if (err)
							throw err

						assert.deepEqual(raw.Item.set.SS, [ 'aaa', 'bbb', 'ccc'  ], {strict: true })
						done()
					})
			})
	})

	it('.update() - test new Set( <MIXED> )', function(done) {
		DynamoDB
			.table($tableName)
			.where('hash').eq('test-updated-old')
			.where('range').eq(1)
			.update({
				set1: new Set(),
				set2: new Set(['a', 1, {} ]),
			}, function(err, data ) {
				if (err)
					throw err

				DynamoDB
					.table($tableName)
					.where('hash').eq('test-updated-old')
					.where('range').eq(1)
					.get(function(err, item, raw ) {
						if (err)
							throw err

						//console.log(JSON.stringify(raw, null, "\t"))
						assert.deepEqual(raw.Item.set1.L, [], {strict: true })
						assert.deepEqual(raw.Item.set2.L, [ { "S": "a" }, { "N": "1" }, { "M": {} }  ], {strict: true })

						done()
					})
			})
	})

	it('update() test empty string', function(done) {
		var $obj = {
			empty_string: '',
		}
		DynamoDB
			.table($tableName)
			.where('hash').eq('test-updated-old')
			.where('range').eq(1)
			.update($obj, function(err, data) {
				if (err)
					throw err

				DynamoDB
					.table($tableName)
					.where('hash').eq('test-updated-old')
					.where('range').eq(1)
					.get(function(err, item) {
						if (err)
							throw err

						assert.deepEqual(item.empty_string, '' )
						done()
					})
			})
	})

	it('.update().then()', function(done) {
		DynamoDB
			.table($tableName)
			.return(DynamoDB.UPDATED_OLD)
			.where('hash').eq('test-updated-old')
			.where('range').eq(1)
			.update({
				number: 1,
			})
			.then(function(data) {
				done()
			})
	})
	it('.update() - unhandled', function(done) {
		DynamoDB
			.table($tableName)
			.where('hash').eq(1)
			.where('range_unexistent').eq(1)
			.update({})
		setTimeout(function() {
			done()
		},5000)
	})
	it('.update().catch()', function(done) {
		DynamoDB
			.table($tableName)
			.where('hash').eq(1)
			.where('range_unexistent').eq(1)
			.update({})
			.catch(function(err) {
				done()
			})
	})

	it('.update() - add() to List, StringSet, NumberSet', function(done) {
		async.waterfall([

			function(cb) {
				DynamoDB
					.table($tableName)
					.insert_or_replace({
						hash: 'test-updated-ss-add',
						range: 1,
						arr: ['x','y'],
						//obj: {number: 1},
						ss: DynamoDB.SS( ['bbb','ccc'] ),
						ns: DynamoDB.NS( [ 33,22] ),
					}, function(err) {
						if (err) throw err
						cb()
					})
			},

			function(cb) {
				DynamoDB
					.table($tableName)
					.where('hash').eq('test-updated-ss-add')
					.where('range').eq(1)
					.update({
						arr: DynamoDB.add( ['x','y', false, null, {}] ),
						//obj: DynamoDB.add( { color: 'blue'} ),
						ss:  DynamoDB.add( DynamoDB.SS(['aaa','ddd']) ),
						ns:  DynamoDB.add( DynamoDB.NS([11,44]) ),

					}, function(err, data ) {
						if (err) throw err

						cb()
					})
			},

		],function(err) {
				DynamoDB
					.table($tableName)
					.where('hash').eq('test-updated-ss-add')
					.where('range').eq(1)
					//.return(DynamoDB.UPDATED_OLD)
					//.on('beforeRequest', function(op, payload) {
					//	console.log(op, JSON.stringify(payload,null,"\t"))
					//})
					.get( function(err, data ) {
						if (err) throw err

						assert.deepEqual(data.arr, [ 'x', 'y', 'x', 'y', false, null, {} ] )
						assert.deepEqual(data.ss, [ 'bbb', 'ccc', 'aaa', 'ddd' ] )
						assert.deepEqual(data.ns.sort(function(a,b) { return a > b ? 1 : -1 }), [ 11, 22, 33, 44 ] )

						done()
					})
		})
	})

	it('.update() - del() from StringSet and NumberSet', function(done) {
		async.waterfall([

			function(cb) {
				DynamoDB
					.table($tableName)
					.insert_or_replace({
						hash: 'test-updated-ss-del',
						range: 1,
						//arr: ['x','y'],
						ss: DynamoDB.SS( ['bbb','ccc'] ),
						ns: DynamoDB.NS( [ 33,22] ),
					}, function(err) {
						if (err) throw err
						cb()
					})
			},

			function(cb) {
				DynamoDB
					.table($tableName)
					.where('hash').eq('test-updated-ss-del')
					.where('range').eq(1)
					.update({

						ss:  DynamoDB.del( DynamoDB.SS(['bbb']) ),
						ns:  DynamoDB.del( DynamoDB.NS([22]) ),

					}, function(err, data ) {
						if (err) throw err

						cb()
					})
			},

		],function(err) {
				DynamoDB
					.table($tableName)
					.where('hash').eq('test-updated-ss-del')
					.where('range').eq(1)
					//.return(DynamoDB.UPDATED_OLD)
					//.on('beforeRequest', function(op, payload) {
					//	console.log(op, JSON.stringify(payload,null,"\t"))
					//})
					.get( function(err, data ) {
						if (err) throw err

						assert.deepEqual(data.ss, [ 'ccc' ] )
						assert.deepEqual(data.ns, [ 33 ] )

						done()
					})
		})
	})

	it('cleanup...', function(done) {
		DynamoDB
			.table($tableName)
			.scan(function(err, data) {
				if (err)
					throw err

				async.each(data, function(item,cb) {
					DynamoDB.table($tableName).where('hash').eq(item.hash).where('range').eq(item.range).delete(function(err) { cb(err) })
				}, function(err) {
					if (err)
						throw err

					done()
				})
			})
	})
})
<|endoftext|>


<commit_before>'use strict';

module.exports = function base(transformer) {
  describe('Transformer: '+ transformer, function () {
    var common = require('./common')
      , request = common.request
      , Primus = common.Primus
      , http = require('http')
      , expect = common.expect
      , Socket
      , server
      , primus;

    beforeEach(function beforeEach(done) {
      server = http.createServer(function (req, res) {
        console.error('Uncaught request', req.url);
        if (req.url !== '/nothrow') throw new Error('I should never be called');

        res.end('original listener');
      });

      primus = new Primus(server, { transformer: transformer });
      Socket = primus.Socket;

      primus.on('connection', function (spark) {
        spark.on('data', function data(packet) {
          if (packet.echo) spark.write(packet.echo);
          if (packet.pipe) require('fs').createReadStream(__filename).pipe(spark, {
            autoClose: false
          });
        });
      });

      server.portnumber = common.port;
      server.listen(server.portnumber, done);
    });

    afterEach(function afterEach(done) {
      primus.forEach(function (spark) {
        spark.end();
      });

      server.close(done);
    });

    describe('.Socket', function () {
      it('exposes a complatible socket', function () {
        expect(Socket).to.be.a('function');
      });

      it('emits an `open` event when its connected', function (done) {
        var socket = new Socket('http://localhost:'+ server.portnumber);

        socket.on('open', function () {
          socket.end();
          done();
        });
      });

      it('should change readyStates', function (done) {
        var socket = new Socket('http://localhost:'+ server.portnumber);

        expect(socket.readyState).to.equal(Socket.OPENING);

        socket.on('open', function () {
          expect(socket.readyState).to.equal(Socket.OPEN);
          socket.end();
        }).on('end', function () {
          expect(socket.readyState).to.equal(Socket.CLOSED);
          done();
        });
      });

      it('emits an `end` event when its closed', function (done) {
        var socket = new Socket('http://localhost:'+ server.portnumber);

        socket.on('open', function () {
          socket.end();
        }).on('end', done);
      });

      it('only emits `end` once', function (done) {
        var socket = new Socket('http://localhost:'+ server.portnumber);

        socket.on('open', function () {
          socket.end();
          socket.end();
          socket.end();
          socket.end();
          socket.end();
          socket.end();
        }).on('end', done);
      });

      it('sends & receives messages', function (done) {
        var socket = new Socket('http://localhost:'+ server.portnumber);

        socket.on('data', function (message) {
          expect(message).to.equal('pong');
          socket.end();
          done();
        });

        socket.on('open', function () {
          socket.write({ echo: 'pong' });
        });
      });

      it('receives the raw packet data', function (done) {
        var socket = new Socket('http://localhost:'+ server.portnumber);

        socket.on('data', function (message, raw) {
          var data = JSON.stringify(message);
          expect(message).to.equal('pong');

          expect(raw).to.not.equal(message);
          expect(data).to.equal(raw);

          socket.end();
          done();
        });

        socket.on('open', function () {
          socket.write({ echo: 'pong' });
        });
      });

      it('emits an `error` event when it cannot encode the data', function (done) {
        var socket = new Socket('http://localhost:'+ server.portnumber);

        socket.on('open', function () {
          var data = { foo: 'bar' };
          data.recusrive = data;

          socket.write(data);
        }).on('error', function (err) {
          expect(err).to.not.be.instanceOf(String);
          expect(err.message).to.contain('JSON');

          socket.end();
          done();
        });
      });

      it('buffers messages before it connected', function (done) {
        var socket = new Socket('http://localhost:'+ server.portnumber)
          , messages = 10
          , received = 0;

        for (var i = 0; i <= messages; i++) {
          socket.write({ echo: i });
        }

        socket.on('data', function (message) {
          expect(message).to.be.a('number');

          if (++received === messages) {
            socket.end();
            done();
          }
        });
      });

      it('should not reconnect when we close the connection', function (done) {
        var socket = new Socket('http://localhost:'+ server.portnumber);

        socket.on('open', function (message) {
          socket.end();
          done();
        });

        socket.on('reconnect', function () {
          throw new Error('fuck');
        });
      });

      it('should reconnect when the connection closes unexcpectingly', function (done) {
        primus.on('connection', function (spark) {
          if (!reconnected) {
            reconnected = true;

            //
            // Forcefully kill a connection to trigger a reconnect
            //
            switch (transformer.toLowerCase()) {
              case 'socket.io':
                primus.transformer.service.transports[spark.id].close();
              break;

              default:
                spark.emit('outgoing::end');
            }
          }
        });

        var socket = new Socket('http://localhost:'+ server.portnumber)
          , reconnected = false
          , reconnect = false
          , opened = 0;

        socket.on('reconnect', function (message) {
          reconnect = true;
        });

        socket.on('open', function () {
          if (++opened !== 2) return;

          expect(reconnect).to.equal(true);

          primus.forEach(function (socket) {
            socket.end();
          });

          done();
        });
      });

      describe('#transform', function () {
        it('thrown an error if an invalid type is given', function (done) {
          var socket = new Socket('http://localhost:'+ server.portnumber);

          primus.on('connection', function (spark) {
            spark.end();
            done();
          });

          try { socket.transform('cowsack', function () {}); }
          catch (e) {
            expect(e.message).to.contain('transformer');
          }
        });

        describe('outgoing', function () {
          it('rewrites the outgoing message', function (done) {
            var socket = new Socket('http://localhost:'+ server.portnumber);

            primus.on('connection', function (spark) {
              spark.on('data', function (data) {
                expect(data).to.be.a('object');
                expect(data.meta).to.equal('meta');
                expect(data.message).to.equal('foo');

                spark.end();
                done();
              });
            });

            socket.transform('outgoing', function (data) {
              expect(data).to.be.a('object');
              expect(data.data).to.equal('foo');

              data.data = {
                message: 'foo',
                meta: 'meta'
              };
            });

            socket.write('foo');
          });

          it('prevents the message from being written', function (done) {
            var socket = new Socket('http://localhost:'+ server.portnumber);

            socket.transform('outgoing', function (data) {
              setTimeout(function () {
                socket.end();
                done();
              }, 0);

              return false;
            });

            socket.on('outgoing::data', function () {
              throw new Error('return false should prevent this emit');
            }).write('foo');
          });
        });

        describe('incoming', function () {
          it('rewrites the incoming message', function (done) {
            var socket = new Socket('http://localhost:'+ server.portnumber);

            primus.on('connection', function (spark) {
              spark.write('foo');
            });

            socket.transform('incoming', function (data) {
              expect(data).to.be.a('object');
              expect(data.data).to.equal('foo');

              data.data = {
                message: 'foo',
                meta: 'meta'
              };
            });

            socket.on('data', function (data) {
              expect(data).to.be.a('object');
              expect(data.meta).to.equal('meta');
              expect(data.message).to.equal('foo');

              socket.end();
              done();
            });
          });

          it('prevents the message from being emitted', function (done) {
            var socket = new Socket('http://localhost:'+ server.portnumber);

            primus.on('connection', function (spark) {
              spark.write('foo');
            });

            socket.transform('incoming', function (data) {
              setTimeout(function () {
                socket.end();
                done();
              }, 0);

              return false;
            });

            socket.on('data', function () {
              throw new Error('return false should prevent this emit');
            });
          });
        });
      });
    });

    describe('.createSocket', function () {
      it('can connect to the server', function (done) {
        var PSocket = Primus.createSocket({ transformer: transformer })
          , socket = new PSocket('http://localhost:'+ server.portnumber);

        socket.on('open', function () {
          socket.end();
          done();
        });
      });
    });

    describe('Server', function () {
      it('emits `end` when the connection is closed', function (done) {
        primus.on('connection', function (spark) {
          spark.on('end', done);
        });

        var socket = new Socket('http://localhost:'+ server.portnumber);

        socket.on('open', function () {
          socket.end();
        });
      });

      it('should emit an `error` when it fails to encode the data', function (done) {
        primus.on('connection', function (spark) {
          var data = { foo: 'bar' };
          data.recusrive = data;

          spark.on('error', function (err) {
            expect(err).to.not.be.a('string');
            expect(err.message).to.include('JSON');

            socket.end();
            done();
          });

          spark.write(data);
        });

        var socket = new Socket('http://localhost:'+ server.portnumber);
      });

      it('should receive querystrings', function (done) {
        primus.on('connection', function (spark) {
          expect(spark.query).to.be.a('object');

          if (
               transformer.toLowerCase() !== 'browserchannel'
            && transformer.toLowerCase() !== 'sockjs'
          ) {
            expect(spark.query.foo).to.equal('bar');
          }

          socket.end();
        });

        var socket = new Socket('http://localhost:'+ server.portnumber +'/?foo=bar');
        socket.on('end', done);
      });

      it('should not trigger a reconnect when we end the connection', function (done) {
        primus.on('connection', function (spark) {
          spark.end();
        });

        var socket = new Socket('http://localhost:'+ server.portnumber);

        socket.on('end', done);
        socket.on('reconnect', function () {
          throw new Error('fuck');
        });
      });

      it('should still allow requests to the original listener', function (done) {
        request(
          'http://localhost:'+ server.portnumber +'/nothrow',
          function (err, res, body) {
            if (err) return done(err);

            expect(body).to.equal('original listener');
            done();
          }
        );
      });

      it('responds to library requests', function (done) {
        request(
          'http://localhost:'+ server.portnumber + '/primus/primus.js',
          function (err, res, body) {
            if (err) return done(err);

            expect(res.statusCode).to.equal(200);
            expect(res.headers['content-type']).to.equal('text/javascript; charset=utf-8');
            expect(body).to.equal(primus.library());
            done();
          }
        );
      });

      it('correctly parses the ip address', function (done) {
        primus.on('connection', function (spark) {
          var address = spark.address;
          expect(address.port).to.not.equal(0);
          expect(address.port).to.not.equal(server.portnumber);

          spark.end();
          done();
        });

        var socket = new Socket('http://localhost:'+ server.portnumber);
      });

      it('uses x-forwarded headers over the connection ip address', function (done) {
        primus.on('connection', function (spark) {
          spark.headers['x-forwarded-for'] = '13.3.37.1,12.12.12.12';
          spark.headers['x-forwarded-port'] = '9083,1334';

          expect(spark.address.ip).to.equal('13.3.37.1');
          expect(spark.address.port).to.equal(9083);

          spark.end();
          done();
        });

        var socket = new Socket('http://localhost:'+ server.portnumber);
      });

      it('exposes a spec file with the correct transformer', function (done) {
        request(
          'http://localhost:'+ server.portnumber +'/primus/spec',
          function (err, res, body) {
            if (err) return done(err);
            body = JSON.parse(body);

            expect(body.transformer).to.equal(transformer.toLowerCase());
            expect(body.version).to.equal(primus.version);
            expect(body.pathname).to.equal('/primus');
            expect(body.parser).to.equal('json');
            done();
          }
        );
      });

      describe('#transform', function () {
        it('thrown an error if an invalid type is given', function (done) {
          try { primus.transform('cowsack', function () {}); }
          catch (e) {
            expect(e.message).to.contain('transformer');
            done();
          }
        });

        describe('outgoing', function () {
          it('rewrites the outgoing message', function (done) {
            primus.transform('outgoing', function (data) {
              expect(data).to.be.a('object');
              expect(data.data).to.equal('foo');

              data.data = {
                message: 'foo',
                meta: 'meta'
              };
            });

            primus.on('connection', function (spark) {
              setTimeout(function () {
                spark.write('foo');
              }, 10);
            });

            var socket = new Socket('http://localhost:'+ server.portnumber);

            socket.on('data', function (data) {
              expect(data).to.be.a('object');
              expect(data.meta).to.equal('meta');
              expect(data.message).to.equal('foo');

              socket.end();
              done();
            });
          });
        });
      });
    });
  });
};
<commit_msg>[test] Adding serverside transformer tests #7<commit_after>'use strict';

module.exports = function base(transformer) {
  describe('Transformer: '+ transformer, function () {
    var common = require('./common')
      , request = common.request
      , Primus = common.Primus
      , http = require('http')
      , expect = common.expect
      , Socket
      , server
      , primus;

    beforeEach(function beforeEach(done) {
      server = http.createServer(function (req, res) {
        console.error('Uncaught request', req.url);
        if (req.url !== '/nothrow') throw new Error('I should never be called');

        res.end('original listener');
      });

      primus = new Primus(server, { transformer: transformer });
      Socket = primus.Socket;

      primus.on('connection', function (spark) {
        spark.on('data', function data(packet) {
          if (packet.echo) spark.write(packet.echo);
          if (packet.pipe) require('fs').createReadStream(__filename).pipe(spark, {
            autoClose: false
          });
        });
      });

      server.portnumber = common.port;
      server.listen(server.portnumber, done);
    });

    afterEach(function afterEach(done) {
      primus.forEach(function (spark) {
        spark.end();
      });

      server.close(done);
    });

    describe('.Socket', function () {
      it('exposes a complatible socket', function () {
        expect(Socket).to.be.a('function');
      });

      it('emits an `open` event when its connected', function (done) {
        var socket = new Socket('http://localhost:'+ server.portnumber);

        socket.on('open', function () {
          socket.end();
          done();
        });
      });

      it('should change readyStates', function (done) {
        var socket = new Socket('http://localhost:'+ server.portnumber);

        expect(socket.readyState).to.equal(Socket.OPENING);

        socket.on('open', function () {
          expect(socket.readyState).to.equal(Socket.OPEN);
          socket.end();
        }).on('end', function () {
          expect(socket.readyState).to.equal(Socket.CLOSED);
          done();
        });
      });

      it('emits an `end` event when its closed', function (done) {
        var socket = new Socket('http://localhost:'+ server.portnumber);

        socket.on('open', function () {
          socket.end();
        }).on('end', done);
      });

      it('only emits `end` once', function (done) {
        var socket = new Socket('http://localhost:'+ server.portnumber);

        socket.on('open', function () {
          socket.end();
          socket.end();
          socket.end();
          socket.end();
          socket.end();
          socket.end();
        }).on('end', done);
      });

      it('sends & receives messages', function (done) {
        var socket = new Socket('http://localhost:'+ server.portnumber);

        socket.on('data', function (message) {
          expect(message).to.equal('pong');
          socket.end();
          done();
        });

        socket.on('open', function () {
          socket.write({ echo: 'pong' });
        });
      });

      it('receives the raw packet data', function (done) {
        var socket = new Socket('http://localhost:'+ server.portnumber);

        socket.on('data', function (message, raw) {
          var data = JSON.stringify(message);
          expect(message).to.equal('pong');

          expect(raw).to.not.equal(message);
          expect(data).to.equal(raw);

          socket.end();
          done();
        });

        socket.on('open', function () {
          socket.write({ echo: 'pong' });
        });
      });

      it('emits an `error` event when it cannot encode the data', function (done) {
        var socket = new Socket('http://localhost:'+ server.portnumber);

        socket.on('open', function () {
          var data = { foo: 'bar' };
          data.recusrive = data;

          socket.write(data);
        }).on('error', function (err) {
          expect(err).to.not.be.instanceOf(String);
          expect(err.message).to.contain('JSON');

          socket.end();
          done();
        });
      });

      it('buffers messages before it connected', function (done) {
        var socket = new Socket('http://localhost:'+ server.portnumber)
          , messages = 10
          , received = 0;

        for (var i = 0; i <= messages; i++) {
          socket.write({ echo: i });
        }

        socket.on('data', function (message) {
          expect(message).to.be.a('number');

          if (++received === messages) {
            socket.end();
            done();
          }
        });
      });

      it('should not reconnect when we close the connection', function (done) {
        var socket = new Socket('http://localhost:'+ server.portnumber);

        socket.on('open', function (message) {
          socket.end();
          done();
        });

        socket.on('reconnect', function () {
          throw new Error('fuck');
        });
      });

      it('should reconnect when the connection closes unexcpectingly', function (done) {
        primus.on('connection', function (spark) {
          if (!reconnected) {
            reconnected = true;

            //
            // Forcefully kill a connection to trigger a reconnect
            //
            switch (transformer.toLowerCase()) {
              case 'socket.io':
                primus.transformer.service.transports[spark.id].close();
              break;

              default:
                spark.emit('outgoing::end');
            }
          }
        });

        var socket = new Socket('http://localhost:'+ server.portnumber)
          , reconnected = false
          , reconnect = false
          , opened = 0;

        socket.on('reconnect', function (message) {
          reconnect = true;
        });

        socket.on('open', function () {
          if (++opened !== 2) return;

          expect(reconnect).to.equal(true);

          primus.forEach(function (socket) {
            socket.end();
          });

          done();
        });
      });

      describe('#transform', function () {
        it('thrown an error if an invalid type is given', function (done) {
          var socket = new Socket('http://localhost:'+ server.portnumber);

          primus.on('connection', function (spark) {
            spark.end();
            done();
          });

          try { socket.transform('cowsack', function () {}); }
          catch (e) {
            expect(e.message).to.contain('transformer');
          }
        });

        describe('outgoing', function () {
          it('rewrites the outgoing message', function (done) {
            var socket = new Socket('http://localhost:'+ server.portnumber);

            primus.on('connection', function (spark) {
              spark.on('data', function (data) {
                expect(data).to.be.a('object');
                expect(data.meta).to.equal('meta');
                expect(data.message).to.equal('foo');

                spark.end();
                done();
              });
            });

            socket.transform('outgoing', function (data) {
              expect(data).to.be.a('object');
              expect(data.data).to.equal('foo');

              data.data = {
                message: 'foo',
                meta: 'meta'
              };
            });

            socket.write('foo');
          });

          it('prevents the message from being written', function (done) {
            var socket = new Socket('http://localhost:'+ server.portnumber);

            socket.transform('outgoing', function (data) {
              setTimeout(function () {
                socket.end();
                done();
              }, 0);

              return false;
            });

            socket.on('outgoing::data', function () {
              throw new Error('return false should prevent this emit');
            }).write('foo');
          });
        });

        describe('incoming', function () {
          it('rewrites the incoming message', function (done) {
            var socket = new Socket('http://localhost:'+ server.portnumber);

            primus.on('connection', function (spark) {
              spark.write('foo');
            });

            socket.transform('incoming', function (data) {
              expect(data).to.be.a('object');
              expect(data.data).to.equal('foo');

              data.data = {
                message: 'foo',
                meta: 'meta'
              };
            });

            socket.on('data', function (data) {
              expect(data).to.be.a('object');
              expect(data.meta).to.equal('meta');
              expect(data.message).to.equal('foo');

              socket.end();
              done();
            });
          });

          it('prevents the message from being emitted', function (done) {
            var socket = new Socket('http://localhost:'+ server.portnumber);

            primus.on('connection', function (spark) {
              spark.write('foo');
            });

            socket.transform('incoming', function (data) {
              setTimeout(function () {
                socket.end();
                done();
              }, 0);

              return false;
            });

            socket.on('data', function () {
              throw new Error('return false should prevent this emit');
            });
          });
        });
      });
    });

    describe('.createSocket', function () {
      it('can connect to the server', function (done) {
        var PSocket = Primus.createSocket({ transformer: transformer })
          , socket = new PSocket('http://localhost:'+ server.portnumber);

        socket.on('open', function () {
          socket.end();
          done();
        });
      });
    });

    describe('Server', function () {
      it('emits `end` when the connection is closed', function (done) {
        primus.on('connection', function (spark) {
          spark.on('end', done);
        });

        var socket = new Socket('http://localhost:'+ server.portnumber);

        socket.on('open', function () {
          socket.end();
        });
      });

      it('should emit an `error` when it fails to encode the data', function (done) {
        primus.on('connection', function (spark) {
          var data = { foo: 'bar' };
          data.recusrive = data;

          spark.on('error', function (err) {
            expect(err).to.not.be.a('string');
            expect(err.message).to.include('JSON');

            socket.end();
            done();
          });

          spark.write(data);
        });

        var socket = new Socket('http://localhost:'+ server.portnumber);
      });

      it('should receive querystrings', function (done) {
        primus.on('connection', function (spark) {
          expect(spark.query).to.be.a('object');

          if (
               transformer.toLowerCase() !== 'browserchannel'
            && transformer.toLowerCase() !== 'sockjs'
          ) {
            expect(spark.query.foo).to.equal('bar');
          }

          socket.end();
        });

        var socket = new Socket('http://localhost:'+ server.portnumber +'/?foo=bar');
        socket.on('end', done);
      });

      it('should not trigger a reconnect when we end the connection', function (done) {
        primus.on('connection', function (spark) {
          spark.end();
        });

        var socket = new Socket('http://localhost:'+ server.portnumber);

        socket.on('end', done);
        socket.on('reconnect', function () {
          throw new Error('fuck');
        });
      });

      it('should still allow requests to the original listener', function (done) {
        request(
          'http://localhost:'+ server.portnumber +'/nothrow',
          function (err, res, body) {
            if (err) return done(err);

            expect(body).to.equal('original listener');
            done();
          }
        );
      });

      it('responds to library requests', function (done) {
        request(
          'http://localhost:'+ server.portnumber + '/primus/primus.js',
          function (err, res, body) {
            if (err) return done(err);

            expect(res.statusCode).to.equal(200);
            expect(res.headers['content-type']).to.equal('text/javascript; charset=utf-8');
            expect(body).to.equal(primus.library());
            done();
          }
        );
      });

      it('correctly parses the ip address', function (done) {
        primus.on('connection', function (spark) {
          var address = spark.address;
          expect(address.port).to.not.equal(0);
          expect(address.port).to.not.equal(server.portnumber);

          spark.end();
          done();
        });

        var socket = new Socket('http://localhost:'+ server.portnumber);
      });

      it('uses x-forwarded headers over the connection ip address', function (done) {
        primus.on('connection', function (spark) {
          spark.headers['x-forwarded-for'] = '13.3.37.1,12.12.12.12';
          spark.headers['x-forwarded-port'] = '9083,1334';

          expect(spark.address.ip).to.equal('13.3.37.1');
          expect(spark.address.port).to.equal(9083);

          spark.end();
          done();
        });

        var socket = new Socket('http://localhost:'+ server.portnumber);
      });

      it('exposes a spec file with the correct transformer', function (done) {
        request(
          'http://localhost:'+ server.portnumber +'/primus/spec',
          function (err, res, body) {
            if (err) return done(err);
            body = JSON.parse(body);

            expect(body.transformer).to.equal(transformer.toLowerCase());
            expect(body.version).to.equal(primus.version);
            expect(body.pathname).to.equal('/primus');
            expect(body.parser).to.equal('json');
            done();
          }
        );
      });

      describe('#transform', function () {
        it('thrown an error if an invalid type is given', function (done) {
          try { primus.transform('cowsack', function () {}); }
          catch (e) {
            expect(e.message).to.contain('transformer');
            done();
          }
        });

        describe('outgoing', function () {
          it('rewrites the outgoing message', function (done) {
            primus.transform('outgoing', function (data) {
              expect(data).to.be.a('object');
              expect(data.data).to.equal('foo');

              data.data = {
                message: 'foo',
                meta: 'meta'
              };
            });

            primus.on('connection', function (spark) {
              setTimeout(function () {
                spark.write('foo');
              }, 10);
            });

            var socket = new Socket('http://localhost:'+ server.portnumber);

            socket.on('data', function (data) {
              expect(data).to.be.a('object');
              expect(data.meta).to.equal('meta');
              expect(data.message).to.equal('foo');

              socket.end();
              done();
            });
          });

          it('prevents the message from being written', function (done) {
            primus.transform('outgoing', function () {
              setTimeout(function () {
                socket.end();
                done();
              }, 0);

              return false;
            });

            primus.on('connection', function (spark) {
              spark.on('outgoing::data', function () {
                throw new Error('return false should prevent this emit');
              });

              spark.write('foo');
            });

            var socket = new Socket('http://localhost:'+ server.portnumber);
          });
        });

        describe('incoming', function () {
          it('rewrites the incoming message', function (done) {
            primus.transform('incoming', function (data) {
              expect(data).to.be.a('object');
              expect(data.data).to.equal('foo');

              data.data = {
                message: 'foo',
                meta: 'meta'
              };
            });

            primus.on('connection', function (spark) {
              spark.on('data', function (data) {
                expect(data).to.be.a('object');
                expect(data.meta).to.equal('meta');
                expect(data.message).to.equal('foo');

                spark.end();
                done();
              });
            });

            var socket = new Socket('http://localhost:'+ server.portnumber);
            socket.write('foo');
          });

          it('prevents the message from being emitted', function (done) {
            primus.transform('incoming', function (data) {
              setTimeout(function () {
                socket.end();
                done();
              }, 0);

              return false;
            });

            primus.on('connection', function (spark) {
              spark.on('data', function () {
                throw new Error('return false should prevent this emit');
              });
            });

            var socket = new Socket('http://localhost:'+ server.portnumber);
            socket.write('foo');
          });
        });
      });
    });
  });
};
<|endoftext|>


<commit_before>const assert = require('assert');
const isArray = require('lodash/isArray');

describe('map', function() {
    let Map = null;
    let Parse = null;

    before(function() {
        Map = require('src/transformers/map');
        Parse = require('src/parse');
    })

    describe('#constructor', function() {
        it('Should create an instance without new keyword when attached', function() {
            const obj = {
                map: Map,
                transform: instance => {
                    assert(instance instanceof Map);
                    assert.equal(instance._callback, callback);
                }
            };

            const callback = function() {};
            obj.map(callback);
        })
    })

    describe('#_createParse', function() {
        it('Should populate the cache correctly', function() {
            const callback = function(p) {
                assert(p instanceof Parse);
                return {
                    parse: () => 'testabcd'
                };
            }
            const instance = new Map(callback);
            instance.parse({ test1: 'test', test2: 'abcd' });

            assert(instance._cache.test1);
            assert(instance._cache.test2);

            const key1 = instance._cache.test1;
            const key2 = instance._cache.test2;
            instance.parse({ test1: 'test', test2: 'abcd' });

            assert(key1 === instance._cache.test1);
            assert(key2 === instance._cache.test2);
        })
    })

    describe('#parse', function() {
        it('Should parse an object correctly', function() {
            const callback = function(p) {
                assert(p instanceof Parse);
                return {
                    parse: () => 'testabcd'
                };
            }
            const instance = new Map(callback);
            const result = instance.parse({ test1: 'test', test2: 'abcd' });

            assert.deepEqual(result, {
                test1: 'testabcd',
                test2: 'testabcd'
            });
        })

        it('Should detect object or array', function() {
            const callback = function(p) {
                assert(p instanceof Parse);
                return {
                    parse: () => 'testabcd'
                };
            }
            const instance = new Map(callback);
            const result = instance.parse([ 'test', 'abcde' ]);

            assert.ok(isArray(result));
            assert.deepEqual(result, [
                'testabcd',
                'testabcd'
            ]);
        })
    })

    describe('#reverse', function() {
        it('Should reverse an object correctly', function() {
            const callback = function(p) {
                assert(p instanceof Parse);
                return {
                    reverse: (v) => ({ test1: v })
                };
            }
            const instance = new Map(callback);
            const result = instance.reverse({ test1: 'test', test2: 'abcd' });

            assert.deepEqual(result, { test1: 'abcd' });
        })

        it('Should detect object or array', function() {
            const callback = function(p) {
                assert(p instanceof Parse);
                return {
                    reverse: (v) => '_' + v
                };
            }
            const instance = new Map(callback);
            const result = instance.reverse([ 'test', 'abcd' ]);

            assert.ok(isArray(result));
            assert.deepEqual(result, [ '_test', '_abcd' ]);
        })
    })
});
<commit_msg>[test][map] Add test that catches bug when using arrays.<commit_after>const assert = require('assert');
const isArray = require('lodash/isArray');

describe('map', function() {
    let Map = null;
    let Parse = null;

    before(function() {
        Map = require('src/transformers/map');
        Parse = require('src/parse');
    })

    describe('#constructor', function() {
        it('Should create an instance without new keyword when attached', function() {
            const obj = {
                map: Map,
                transform: instance => {
                    assert(instance instanceof Map);
                    assert.equal(instance._callback, callback);
                }
            };

            const callback = function() {};
            obj.map(callback);
        })
    })

    describe('#_createParse', function() {
        it('Should populate the cache correctly', function() {
            const callback = function(p) {
                assert(p instanceof Parse);
                return {
                    parse: () => 'testabcd'
                };
            }
            const instance = new Map(callback);
            instance.parse({ test1: 'test', test2: 'abcd' });

            assert(instance._cache.test1);
            assert(instance._cache.test2);

            const key1 = instance._cache.test1;
            const key2 = instance._cache.test2;
            instance.parse({ test1: 'test', test2: 'abcd' });

            assert(key1 === instance._cache.test1);
            assert(key2 === instance._cache.test2);
        })
    })

    describe('#parse', function() {
        it('Should parse an object correctly', function() {
            const callback = function(p) {
                assert(p instanceof Parse);
                return {
                    parse: () => 'testabcd'
                };
            }
            const instance = new Map(callback);
            const result = instance.parse({ test1: 'test', test2: 'abcd' });

            assert.deepEqual(result, {
                test1: 'testabcd',
                test2: 'testabcd'
            });
        })

        it('Should parse an array correctly', function() {
            const callback = function(p) {
                assert(p instanceof Parse);
                assert(p._chain[0]);
                assert.notEqual(typeof p._chain[0]._path, 'undefined');

                return {
                    parse: (v) => '_' + v[p._chain[0]._path]
                };
            }
            const instance = new Map(callback);
            const result = instance.parse([ 'test', 'abcd' ]);

            assert.deepEqual(result, [
                '_test',
                '_abcd'
            ]);
        })

        it('Should detect object or array', function() {
            const callback = function(p) {
                assert(p instanceof Parse);
                return {
                    parse: () => 'testabcd'
                };
            }
            const instance = new Map(callback);
            const result = instance.parse([ 'test', 'abcde' ]);

            assert.ok(isArray(result));
            assert.deepEqual(result, [
                'testabcd',
                'testabcd'
            ]);
        })
    })

    describe('#reverse', function() {
        it('Should reverse an object correctly', function() {
            const callback = function(p) {
                assert(p instanceof Parse);
                return {
                    reverse: (v) => ({ test1: v })
                };
            }
            const instance = new Map(callback);
            const result = instance.reverse({ test1: 'test', test2: 'abcd' });

            assert.deepEqual(result, { test1: 'abcd' });
        })

        it('Should detect object or array', function() {
            const callback = function(p) {
                assert(p instanceof Parse);
                return {
                    reverse: (v) => '_' + v
                };
            }
            const instance = new Map(callback);
            const result = instance.reverse([ 'test', 'abcd' ]);

            assert.ok(isArray(result));
            assert.deepEqual(result, [ '_test', '_abcd' ]);
        })
    })
});
<|endoftext|>


<commit_before>describe('LinkedList', function() {
  beforeEach(function() {
    this.list = new LinkedList();
    this.a = { str: 'a' };
    this.b = { str: 'b' };
    this.c = { str: 'c' };
    this.a.getLength = this.b.getLength = this.c.getLength = function() {
      return 3;
    };
  });

  describe('manipulation', function() {
    it('append to empty list', function() {
      this.list.append(this.a);
      expect(this.list.length).toEqual(1);
      expect(this.list.head).toEqual(this.a);
      expect(this.list.tail).toEqual(this.a);
      expect(this.a.prev).toBeUndefined();
      expect(this.a.next).toBeUndefined();
    });

    it('insert to become head', function() {
      this.list.append(this.b);
      this.list.insertBefore(this.a, this.b);
      expect(this.list.length).toEqual(2);
      expect(this.list.head).toEqual(this.a);
      expect(this.list.tail).toEqual(this.b);
      expect(this.a.prev).toBeUndefined();
      expect(this.a.next).toEqual(this.b);
      expect(this.b.prev).toEqual(this.a);
      expect(this.b.next).toBeUndefined();
    });

    it('insert to become tail', function() {
      this.list.append(this.a);
      this.list.insertBefore(this.b, undefined);
      expect(this.list.length).toEqual(2);
      expect(this.list.head).toEqual(this.a);
      expect(this.list.tail).toEqual(this.b);
      expect(this.a.prev).toBeUndefined();
      expect(this.a.next).toEqual(this.b);
      expect(this.b.prev).toEqual(this.a);
      expect(this.b.next).toBeUndefined();
    });

    it('insert in middle', function() {
      this.list.append(this.a, this.c);
      this.list.insertBefore(this.b, this.c);
      expect(this.list.length).toEqual(3);
      expect(this.list.head).toEqual(this.a);
      expect(this.a.next).toEqual(this.b);
      expect(this.b.next).toEqual(this.c);
      expect(this.list.tail).toEqual(this.c);
    });

    it('remove head', function() {
      this.list.append(this.a, this.b);
      this.list.remove(this.a);
      expect(this.list.length).toEqual(1);
      expect(this.list.head).toEqual(this.b);
      expect(this.list.tail).toEqual(this.b);
      expect(this.list.head.prev).toBeUndefined();
      expect(this.list.tail.next).toBeUndefined();
    });

    it('remove tail', function() {
      this.list.append(this.a, this.b);
      this.list.remove(this.b);
      expect(this.list.length).toEqual(1);
      expect(this.list.head).toEqual(this.a);
      expect(this.list.tail).toEqual(this.a);
      expect(this.list.head.prev).toBeUndefined();
      expect(this.list.tail.next).toBeUndefined();
    });

    it('remove inner', function() {
      this.list.append(this.a, this.b, this.c);
      this.list.remove(this.b);
      expect(this.list.length).toEqual(2);
      expect(this.list.head).toEqual(this.a);
      expect(this.list.tail).toEqual(this.c);
      expect(this.list.head.prev).toBeUndefined();
      expect(this.list.tail.next).toBeUndefined();
      expect(this.a.next).toEqual(this.c);
      expect(this.c.prev).toEqual(this.a);
      // Maintain references
      expect(this.b.prev).toEqual(this.a);
      expect(this.b.next).toEqual(this.c);
    });

    it('remove only node', function() {
      this.list.append(this.a);
      this.list.remove(this.a);
      expect(this.list.length).toEqual(0);
      expect(this.list.head).toBeUndefined();
      expect(this.list.tail).toBeUndefined();
    });

    it('empty', function() {
      this.list.append(this.a, this.b);
      this.list.empty();
      expect(this.list.length).toEqual(0);
      expect(this.list.head).toBeUndefined();
      expect(this.list.tail).toBeUndefined();
    });

    it('move', function() {
      this.list.append(this.a, this.b, this.c);
      this.list.remove(this.b);
      this.list.remove(this.a);
      this.list.remove(this.c);
      this.list.append(this.b);
      expect(this.b.prev).toBeUndefined();
      expect(this.b.next).toBeUndefined();
    });
  });

  describe('iteration', function() {
    beforeEach(function() {
      this.spy = {
        callback: function() {
          return arguments;
        }
      };
      spyOn(this.spy, 'callback');
    });

    it('iterate over empty list', function() {
      this.list.forEach(this.spy.callback)
      expect(this.spy.callback.calls.count()).toEqual(0)
    });

    it('iterate non-head start', function() {
      this.list.append(this.a, this.b, this.c);
      var next = this.list.iterator(this.b);
      var b = next();
      var c = next();
      var d = next();
      expect(b).toEqual(this.b);
      expect(c).toEqual(this.c);
      expect(d).toBeUndefined();
    });

    it('find', function() {
      this.list.append(this.a, this.b, this.c);
      expect(this.list.find(0)).toEqual([this.a, 0]);
      expect(this.list.find(2)).toEqual([this.a, 2]);
      expect(this.list.find(3)).toEqual([this.b, 0]);
      expect(this.list.find(4)).toEqual([this.b, 1]);
      expect(this.list.find(10)).toEqual([null, 0]);
    });

    it('offset', function() {
      this.list.append(this.a, this.b, this.c);
      expect(this.list.offset(this.a)).toEqual(0);
      expect(this.list.offset(this.b)).toEqual(3);
      expect(this.list.offset(this.c)).toEqual(6);
    });

    it('forEach', function() {
      this.list.append(this.a, this.b, this.c);
      this.list.forEach(this.spy.callback);
      expect(this.spy.callback.calls.count()).toEqual(3);
      var result = this.spy.callback.calls.all().reduce(function(memo, call) {
        return memo + call.args[0].str;
      }, '');
      expect(result).toEqual('abc');
    });

    it('map', function() {
      this.list.append(this.a, this.b, this.c);
      var arr = this.list.map(function(node) {
        return node.str;
      });
      expect(arr).toEqual(['a', 'b', 'c']);
    });

    it('reduce', function() {
      this.list.append(this.a, this.b, this.c);
      var memo = this.list.reduce(function(memo, node) {
        return memo + node.str;
      }, '');
      expect(memo).toEqual('abc');
    });

    it('forEachAt', function() {
      this.list.append(this.a, this.b, this.c);
      this.list.forEachAt(3, 3, this.spy.callback);
      expect(this.spy.callback.calls.count()).toEqual(1);
      expect(this.spy.callback.calls.first().args).toEqual([this.b, 0, 3]);
    });

    it('forEachAt none', function() {
      this.list.append(this.a, this.b);
      this.list.forEachAt(1, 0, this.spy.callback);
      expect(this.spy.callback.calls.count()).toEqual(0);
    });

    it('forEachAt partial nodes', function() {
      this.list.append(this.a, this.b, this.c);
      this.list.forEachAt(1, 7, this.spy.callback);
      expect(this.spy.callback.calls.count()).toEqual(3);
      var calls = this.spy.callback.calls.all();
      expect(calls[0].args).toEqual([this.a, 1, 2]);
      expect(calls[1].args).toEqual([this.b, 0, 3]);
      expect(calls[2].args).toEqual([this.c, 0, 2]);
    });

    it('forEachAt at part of single node', function() {
      this.list.append(this.a, this.b, this.c);
      this.list.forEachAt(4, 1, this.spy.callback);
      expect(this.spy.callback.calls.count()).toEqual(1);
      expect(this.spy.callback.calls.first().args).toEqual([this.b, 1, 1]);
    });
  });
});
<commit_msg>Use toBe when appropriate<commit_after>describe('LinkedList', function() {
  beforeEach(function() {
    this.list = new LinkedList();
    this.a = { str: 'a' };
    this.b = { str: 'b' };
    this.c = { str: 'c' };
    this.a.getLength = this.b.getLength = this.c.getLength = function() {
      return 3;
    };
  });

  describe('manipulation', function() {
    it('append to empty list', function() {
      this.list.append(this.a);
      expect(this.list.length).toBe(1);
      expect(this.list.head).toBe(this.a);
      expect(this.list.tail).toBe(this.a);
      expect(this.a.prev).toBeUndefined();
      expect(this.a.next).toBeUndefined();
    });

    it('insert to become head', function() {
      this.list.append(this.b);
      this.list.insertBefore(this.a, this.b);
      expect(this.list.length).toBe(2);
      expect(this.list.head).toBe(this.a);
      expect(this.list.tail).toBe(this.b);
      expect(this.a.prev).toBeUndefined();
      expect(this.a.next).toBe(this.b);
      expect(this.b.prev).toBe(this.a);
      expect(this.b.next).toBeUndefined();
    });

    it('insert to become tail', function() {
      this.list.append(this.a);
      this.list.insertBefore(this.b, undefined);
      expect(this.list.length).toBe(2);
      expect(this.list.head).toBe(this.a);
      expect(this.list.tail).toBe(this.b);
      expect(this.a.prev).toBeUndefined();
      expect(this.a.next).toBe(this.b);
      expect(this.b.prev).toBe(this.a);
      expect(this.b.next).toBeUndefined();
    });

    it('insert in middle', function() {
      this.list.append(this.a, this.c);
      this.list.insertBefore(this.b, this.c);
      expect(this.list.length).toBe(3);
      expect(this.list.head).toBe(this.a);
      expect(this.a.next).toBe(this.b);
      expect(this.b.next).toBe(this.c);
      expect(this.list.tail).toBe(this.c);
    });

    it('remove head', function() {
      this.list.append(this.a, this.b);
      this.list.remove(this.a);
      expect(this.list.length).toBe(1);
      expect(this.list.head).toBe(this.b);
      expect(this.list.tail).toBe(this.b);
      expect(this.list.head.prev).toBeUndefined();
      expect(this.list.tail.next).toBeUndefined();
    });

    it('remove tail', function() {
      this.list.append(this.a, this.b);
      this.list.remove(this.b);
      expect(this.list.length).toBe(1);
      expect(this.list.head).toBe(this.a);
      expect(this.list.tail).toBe(this.a);
      expect(this.list.head.prev).toBeUndefined();
      expect(this.list.tail.next).toBeUndefined();
    });

    it('remove inner', function() {
      this.list.append(this.a, this.b, this.c);
      this.list.remove(this.b);
      expect(this.list.length).toBe(2);
      expect(this.list.head).toBe(this.a);
      expect(this.list.tail).toBe(this.c);
      expect(this.list.head.prev).toBeUndefined();
      expect(this.list.tail.next).toBeUndefined();
      expect(this.a.next).toBe(this.c);
      expect(this.c.prev).toBe(this.a);
      // Maintain references
      expect(this.b.prev).toBe(this.a);
      expect(this.b.next).toBe(this.c);
    });

    it('remove only node', function() {
      this.list.append(this.a);
      this.list.remove(this.a);
      expect(this.list.length).toBe(0);
      expect(this.list.head).toBeUndefined();
      expect(this.list.tail).toBeUndefined();
    });

    it('empty', function() {
      this.list.append(this.a, this.b);
      this.list.empty();
      expect(this.list.length).toBe(0);
      expect(this.list.head).toBeUndefined();
      expect(this.list.tail).toBeUndefined();
    });

    it('move', function() {
      this.list.append(this.a, this.b, this.c);
      this.list.remove(this.b);
      this.list.remove(this.a);
      this.list.remove(this.c);
      this.list.append(this.b);
      expect(this.b.prev).toBeUndefined();
      expect(this.b.next).toBeUndefined();
    });
  });

  describe('iteration', function() {
    beforeEach(function() {
      this.spy = {
        callback: function() {
          return arguments;
        }
      };
      spyOn(this.spy, 'callback');
    });

    it('iterate over empty list', function() {
      this.list.forEach(this.spy.callback)
      expect(this.spy.callback.calls.count()).toBe(0)
    });

    it('iterate non-head start', function() {
      this.list.append(this.a, this.b, this.c);
      var next = this.list.iterator(this.b);
      var b = next();
      var c = next();
      var d = next();
      expect(b).toBe(this.b);
      expect(c).toBe(this.c);
      expect(d).toBeUndefined();
    });

    it('find', function() {
      this.list.append(this.a, this.b, this.c);
      expect(this.list.find(0)).toEqual([this.a, 0]);
      expect(this.list.find(2)).toEqual([this.a, 2]);
      expect(this.list.find(3)).toEqual([this.b, 0]);
      expect(this.list.find(4)).toEqual([this.b, 1]);
      expect(this.list.find(10)).toEqual([null, 0]);
    });

    it('offset', function() {
      this.list.append(this.a, this.b, this.c);
      expect(this.list.offset(this.a)).toBe(0);
      expect(this.list.offset(this.b)).toBe(3);
      expect(this.list.offset(this.c)).toBe(6);
    });

    it('forEach', function() {
      this.list.append(this.a, this.b, this.c);
      this.list.forEach(this.spy.callback);
      expect(this.spy.callback.calls.count()).toBe(3);
      var result = this.spy.callback.calls.all().reduce(function(memo, call) {
        return memo + call.args[0].str;
      }, '');
      expect(result).toBe('abc');
    });

    it('map', function() {
      this.list.append(this.a, this.b, this.c);
      var arr = this.list.map(function(node) {
        return node.str;
      });
      expect(arr).toEqual(['a', 'b', 'c']);
    });

    it('reduce', function() {
      this.list.append(this.a, this.b, this.c);
      var memo = this.list.reduce(function(memo, node) {
        return memo + node.str;
      }, '');
      expect(memo).toBe('abc');
    });

    it('forEachAt', function() {
      this.list.append(this.a, this.b, this.c);
      this.list.forEachAt(3, 3, this.spy.callback);
      expect(this.spy.callback.calls.count()).toBe(1);
      expect(this.spy.callback.calls.first().args).toEqual([this.b, 0, 3]);
    });

    it('forEachAt none', function() {
      this.list.append(this.a, this.b);
      this.list.forEachAt(1, 0, this.spy.callback);
      expect(this.spy.callback.calls.count()).toBe(0);
    });

    it('forEachAt partial nodes', function() {
      this.list.append(this.a, this.b, this.c);
      this.list.forEachAt(1, 7, this.spy.callback);
      expect(this.spy.callback.calls.count()).toBe(3);
      var calls = this.spy.callback.calls.all();
      expect(calls[0].args).toEqual([this.a, 1, 2]);
      expect(calls[1].args).toEqual([this.b, 0, 3]);
      expect(calls[2].args).toEqual([this.c, 0, 2]);
    });

    it('forEachAt at part of single node', function() {
      this.list.append(this.a, this.b, this.c);
      this.list.forEachAt(4, 1, this.spy.callback);
      expect(this.spy.callback.calls.count()).toBe(1);
      expect(this.spy.callback.calls.first().args).toEqual([this.b, 1, 1]);
    });
  });
});
<|endoftext|>