bemusic/bemuse

View on GitHub
packages/bemuse-indexer/src/index.spec.ts

Summary

Maintainability
B
4 hrs
Test Coverage
import { BPMInfo, OutputSongInfo } from './types'
import { expect } from 'chai'
import * as indexer from '.'

describe('getFileInfo (bms)', function () {
  function info(source: string) {
    return indexer.getFileInfo(Buffer.from(source), { name: 'meow.bms' })
  }

  describe('.md5', function () {
    it('should return hash', async function () {
      return expect((await info('')).md5).to.equal(
        'd41d8cd98f00b204e9800998ecf8427e'
      )
    })
  })

  describe('.info', function () {
    it('should return song info', async function () {
      const source = '#TITLE meow'
      return expect((await info(source)).info.title).to.equal('meow')
    })
  })

  describe('.noteCount', function () {
    it('should not count BGM', async function () {
      const source = '#00101:01'
      return expect((await info(source)).noteCount).to.equal(0)
    })
    it('should count playable notes', async function () {
      const source = '#00111:01'
      return expect((await info(source)).noteCount).to.equal(1)
    })
  })

  describe('.scratch', function () {
    it('is false when no scratch track', async function () {
      const source = '#00101:01'
      return expect((await info(source)).scratch).to.be.false
    })
    it('should count playable notes', async function () {
      const source = '#00116:01'
      return expect((await info(source)).scratch).to.be.true
    })
  })

  describe('.keys', function () {
    it('should be empty when no notes', async function () {
      const source = '#00101:01'
      return expect((await info(source)).keys).to.equal('empty')
    })
    it('should be 7K on normal chart', async function () {
      const source = ['#00111:01', '#00114:01', '#00159:0101'].join('\n')
      return expect((await info(source)).keys).to.equal('7K')
    })
    it('should be 5K when 6th and 7th keys not detected', async function () {
      const source = ['#00111:01', '#00114:01'].join('\n')
      return expect((await info(source)).keys).to.equal('5K')
    })
    it('should be 14K on doubles chart', async function () {
      const source = [
        '#00111:01',
        '#00114:01',
        '#00159:0101',
        '#00121:01',
        '#00124:01',
        '#00129:0101',
      ].join('\n')
      return expect((await info(source)).keys).to.equal('14K')
    })
    it(
      'should be 10K when 2 players and ' + '6th and 7th keys not detected',
      async function () {
        const source = [
          '#00111:01',
          '#00114:01',
          '#00121:01',
          '#00124:01',
        ].join('\n')
        return expect((await info(source)).keys).to.equal('10K')
      }
    )
  })

  describe('.duration', function () {
    it('should be correct', async function () {
      const source = ['#BPM 120', '#00111:0101'].join('\n')
      return expect((await info(source)).duration).to.equal(3)
    })
  })

  describe('.bpm', function () {
    const source = [
      '#BPM 120',
      '#BPM01 240',
      '#00111:01',
      '#00108:01',
      '#00203:3C78',
      '#00211:01',
      '#00311:01',
    ].join('\n')

    let bpm: BPMInfo

    beforeEach(async function () {
      const fileInfo = await info(source)
      bpm = fileInfo.bpm
    })

    it('init should be the BPM at first beat', function () {
      expect(bpm.init).to.equal(120)
    })
    it('median should be the median BPM', function () {
      expect(bpm.median).to.equal(120)
    })
    it('min should be the minimum BPM', function () {
      expect(bpm.min).to.equal(60)
    })
    it('max should be the maximum BPM', function () {
      expect(bpm.max).to.equal(240)
    })
  })

  describe('.bga', function () {
    it('should be undefined for songs without bga', async function () {
      const source = ['#BPM 120', '#00111:0101'].join('\n')
      return expect((await info(source)).bga).to.equal(undefined)
    })
    it('should exist for songs with bga', async function () {
      const source = [
        '#BPM 120',
        '#BMPBG meow.mpg',
        '#00111:0101',
        '#00104:01BG',
      ].join('\n')
      return expect((await info(source)).bga).to.deep.equal({
        file: 'meow.mpg',
        offset: 3,
      })
    })
  })
})

describe('getFileInfo (bmson)', function () {
  function info(bmson: any) {
    const source = JSON.stringify(bmson)
    return indexer.getFileInfo(Buffer.from(source), { name: 'meow.bmson' })
  }

  describe('.info', function () {
    it('should return song info', async function () {
      const out = await info({ info: { title: 'Running Out' } })
      return expect(out.info.title).to.equal('Running Out')
    })
  })

  describe('.bga', function () {
    it('is undefined if no bga', async function () {
      const out = await info({ info: { title: 'Running Out' } })
      return expect(out.bga).to.equal(undefined)
    })
    it('has timing ', async function () {
      const bmsonData = {
        version: '1.0.0',
        info: {
          title: 'Meow',
          init_bpm: 42,
        },
        bga: {
          bga_events: [{ id: 1, y: 240 }],
          bga_header: [{ id: 1, name: 'meow.mp4' }],
        },
      }
      const out = await info(bmsonData)
      return expect(out.bga).to.deep.equal({
        file: 'meow.mp4',
        offset: 60 / 42,
      })
    })
  })
})

describe('getSongInfo', function () {
  describe('with multiple files', function () {
    const files = [
      {
        name: '01.bms',
        data: Buffer.from(
          '#TITLE meow [NORMAL]\n' +
            '#ARTIST lol\n' +
            '#PLAYLEVEL 5\n' +
            '#BPM 123\n' +
            '#00111:1111'
        ),
      },
      {
        name: '02.bms',
        data: Buffer.from(
          '#TITLE meow [HYPER]\n' +
            '#ARTIST lol\n' +
            '#PLAYLEVEL 7\n' +
            '#BPM 123\n' +
            '#00111:1111'
        ),
      },
      {
        name: '03.bms',
        data: Buffer.from(
          '#TITLE meow [ANOTHER]\n' +
            '#ARTIST lol\n' +
            '#PLAYLEVEL 12\n' +
            '#BPM 123\n' +
            '#00111:1111'
        ),
      },
    ]

    let song: OutputSongInfo

    beforeEach(async function () {
      const songInfo = await indexer.getSongInfo(files)
      song = songInfo
    })

    describe('title', function () {
      it('should be correct', function () {
        expect(song.title).to.equal('meow')
      })
    })
    describe('artist', function () {
      it('should be correct', function () {
        expect(song.artist).to.equal('lol')
      })
      it('should be overridable', async function () {
        const options = { extra: { artist: 'meowmeow' } }
        const out = await indexer.getSongInfo(files, options)
        return expect(out.artist).to.equal('meowmeow')
      })
    })
    describe('charts', function () {
      it('should be an array of charts', function () {
        expect(song.charts).to.have.length(3)
      })
      it('should have the file key', function () {
        expect(song.charts[0].file).to.match(/\.bms/)
      })
    })
    describe('progress report', function () {
      it('should report progress', function () {
        const options = { onProgress: onProgress }
        let callCount = 0
        function onProgress() {
          callCount += 1
        }
        return indexer.getSongInfo(files, options).then(function () {
          expect(callCount).to.equal(3)
        })
      })
    })
  })

  describe('a song’s video', function () {
    it('is taken from an available bga in a chart', function () {
      const charts = [{}, { bga: { file: 'a.mp4', offset: 2 } }, {}] as any
      expect(indexer._getSongVideoFromCharts(charts).video_file).to.equal(
        'a.mp4'
      )
      expect(indexer._getSongVideoFromCharts(charts).video_offset).to.equal(2)
    })
  })
})