require 'spec_helper'
require 'wgif/video'

describe WGif::Video do
  let(:clip) { double(FFMPEG::Movie) }

  before do
    allow(FFMPEG::Movie).to receive(:new).and_return(clip)
  end

  it 'has a name and filepath' do
    expect(clip).to receive(:path).and_return('/tmp/wgif/bjork.mp4')
    video = described_class.new 'bjork', '/tmp/wgif/bjork.mp4'
    expect(video.name).to eq('bjork')
    expect(video.clip.path).to eq('/tmp/wgif/bjork.mp4')
  end

  it 'sets up a logger' do
    video = described_class.new 'bjork', '/tmp/wgif/bjork.mp4'
    expect(video.logger.instance_variable_get(:@logdev).filename)
      .to eq('/tmp/wgif/bjork.log')
  end

  it 'redirects FFMPEG log output to a file' do
    expect(FFMPEG).to receive(:logger=).with(an_instance_of(Logger))
    described_class.new 'penguin', 'spec/fixtures/penguin.mp4'
  end

  it 'is trimmable' do
    expect(clip).to receive(:duration).and_return(5.0)
    expect(clip).to receive(:transcode)
    video = described_class.new 'bjork', '/tmp/wgif/bjork.mp4'
    video = video.trim('00:00:00', 5.0)
    expect(video.clip.duration).to eq(5.0)
  end

  it 'returns its frames' do
    expect(clip).to receive(:transcode)
    allow(FileUtils).to receive(:rm)
    fake_frames = ['one', 'two', 'three']
    expect(Dir).to receive(:glob).with('/tmp/wgif/frames/*.png').twice
      .and_return(fake_frames)
    video = described_class.new 'bjork', '/tmp/wgif/bjork.mp4'
    frames = video.to_frames
    expect(frames.count).to eq(3)
  end

  it 'returns a specific number of frames' do
    frames = '/tmp/wgif/frames/%5d.png'
    options = '-vf fps=5'
    expect(clip).to receive(:transcode).with(frames, options)
    allow(FileUtils).to receive(:rm)
    expect(clip).to receive(:duration).and_return 2
    expect(Dir).to receive(:glob).with('/tmp/wgif/frames/*.png')
      .twice.and_return([])
    video = described_class.new 'bjork', '/tmp/wgif/bjork.mp4'
    video.to_frames(frames: 10)
  end

  it 'catches transcode errors and raises an exception' do
    expect(clip).to receive(:transcode).and_raise(FFMPEG::Error)
    video = described_class.new 'bjork', '/tmp/wgif/bjork.mp4'
    expect { video.trim('00:00:00', 5.0) }
      .to raise_error(WGif::ClipEncodingException)
  end

  it 'silences transcode errors from ripping frames' do
    expect(clip).to receive(:transcode)
      .and_raise(FFMPEG::Error.new 'no output file created')
    video = described_class.new 'bjork', '/tmp/wgif/bjork.mp4'
    expect { video.trim('00:00:00', 5.0) }
      .not_to raise_error
  end

  it 'silences transcode errors from ripping frames when input is invalid' do
    message = 'no output file created. Invalid data found when processing input'
    expect(clip).to receive(:transcode).and_raise(FFMPEG::Error.new message)
    video = described_class.new 'bjork', '/tmp/wgif/bjork.mp4'
    expect { video.trim('00:00:00', 5.0) }
      .to raise_error(WGif::ClipEncodingException)
  end

  it 'sorts frames in lexicographic order' do
    frames = '/tmp/wgif/frames/%5d.png'
    options = '-vf fps=24'
    expect(clip).to receive(:transcode).with(frames, options)
    allow(FileUtils).to receive(:rm)
    unsorted_files = ['001.png', '003.png', '002.png']
    expect(Dir).to receive(:glob).with('/tmp/wgif/frames/*.png')
      .twice.and_return(unsorted_files)
    video = described_class.new 'bjork', '/tmp/wgif/bjork.mp4'
    expect(video.to_frames).to eq(['001.png', '002.png', '003.png'])
  end
end
