#!/usr/bin/python3
#
# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import codecs
import copy
import credits_updater as cu
import os
import unittest

# Assumes this script is in ffmpeg/chromium/scripts/
SOURCE_DIR = os.path.join(
    os.path.dirname(os.path.abspath(__file__)), os.path.pardir, os.path.pardir)
OUTPUT_FILE = 'CREDITS.testing'

# Expected credits for swresample.h applied with the rot13 encoding. Otherwise
# license scanners get confused about the license of this file.
SWRESAMPLE_H_LICENSE_ROT_13 = """yvofjerfnzcyr/fjerfnzcyr.u

Pbclevtug (P) 2011-2013 Zvpunry Avrqreznlre (zvpunryav@tzk.ng)

Guvf svyr vf cneg bs yvofjerfnzcyr

yvofjerfnzcyr vf serr fbsgjner; lbh pna erqvfgevohgr vg naq/be
zbqvsl vg haqre gur grezf bs gur TAH Yrffre Trareny Choyvp
Yvprafr nf choyvfurq ol gur Serr Fbsgjner Sbhaqngvba; rvgure
irefvba 2.1 bs gur Yvprafr, be (ng lbhe bcgvba) nal yngre irefvba.

yvofjerfnzcyr vf qvfgevohgrq va gur ubcr gung vg jvyy or hfrshy,
ohg JVGUBHG NAL JNEENAGL; jvgubhg rira gur vzcyvrq jneenagl bs
ZREPUNAGNOVYVGL be SVGARFF SBE N CNEGVPHYNE CHECBFR.  Frr gur TAH
Yrffre Trareny Choyvp Yvprafr sbe zber qrgnvyf.

Lbh fubhyq unir erprvirq n pbcl bs gur TAH Yrffre Trareny Choyvp
Yvprafr nybat jvgu yvofjerfnzcyr; vs abg, jevgr gb gur Serr Fbsgjner
Sbhaqngvba, Vap., 51 Senaxyva Fgerrg, Svsgu Sybbe, Obfgba, ZN 02110-1301 HFN"""

# The real expected credits for swresample.h.
SWRESAMPLE_H_LICENSE = codecs.decode(SWRESAMPLE_H_LICENSE_ROT_13, 'rot13')


def NewCreditsUpdater():
  return cu.CreditsUpdater(SOURCE_DIR, OUTPUT_FILE)


class CreditsUpdaterUnittest(unittest.TestCase):

  def tearDown(self):
    # Cleanup the testing output file
    test_credits = os.path.join(SOURCE_DIR, OUTPUT_FILE)
    if os.path.exists(test_credits):
      os.remove(test_credits)

  def testNoFiles(self):
    # Write credits without processing any files.
    NewCreditsUpdater().WriteCredits()

    # Credits should *always* have LICENSE.md followed by full LGPL text.
    expected_lines = NormalizeNewLines(GetLicenseMdLines() +
                                       GetSeparatorLines() +
                                       GetLicenseLines(cu.License.LGPL))
    credits_lines = ReadCreditsLines()
    self.assertEqual(expected_lines, credits_lines)

  def testLPGLFiles(self):
    # Process two known LGPL files
    updater = NewCreditsUpdater()
    updater.ProcessFile('libavformat/mp3dec.c')
    updater.ProcessFile('libavformat/mp3enc.c')
    updater.WriteCredits()

    # Expect output to have just LGPL text (once) preceded by LICENSE.md
    expected_lines = NormalizeNewLines(GetLicenseMdLines() +
                                       GetSeparatorLines() +
                                       GetLicenseLines(cu.License.LGPL))
    credits_lines = ReadCreditsLines()
    self.assertEqual(expected_lines, credits_lines)

  def testKnownBucketFiles(self):
    # Process some JPEG and MIPS files.
    updater = NewCreditsUpdater()
    updater.ProcessFile('libavcodec/jfdctfst.c')
    updater.ProcessFile('libavutil/mips/float_dsp_mips.c')
    updater.WriteCredits()

    # Expected output to have JPEG and MIPS text in addition to the typical LGPL
    # and LICENSE.md header. JPEG should appear before MIPS because known
    # buckets will be printed in alphabetical order.
    expected_lines = NormalizeNewLines(
        GetLicenseMdLines() + GetSeparatorLines() +
        ['libavcodec/jfdctfst.c\n\n'] + GetLicenseLines(cu.License.JPEG) +
        GetSeparatorLines() + ['libavutil/mips/float_dsp_mips.c\n\n'] +
        GetLicenseLines(cu.License.MIPS) + GetSeparatorLines() +
        GetLicenseLines(cu.License.LGPL))
    credits_lines = ReadCreditsLines()
    self.assertEqual(expected_lines, credits_lines)

  def testGeneratedAndKnownLicences(self):
    # Process a file that doesn't fall into a known bucket (e.g. the license
    # header for this file is unique). Also process a known bucket file.
    updater = NewCreditsUpdater()
    updater.ProcessFile('libswresample/swresample.h')
    updater.ProcessFile('libavutil/mips/float_dsp_mips.c')
    updater.WriteCredits()

    # Expect output to put swresample.h header first, followed by MIPS.
    expected_lines = NormalizeNewLines(
        GetLicenseMdLines() + GetSeparatorLines() +
        SWRESAMPLE_H_LICENSE.splitlines(True) + GetSeparatorLines() +
        ['libavutil/mips/float_dsp_mips.c\n\n'] +
        GetLicenseLines(cu.License.MIPS) + GetSeparatorLines() +
        GetLicenseLines(cu.License.LGPL))
    credits_lines = ReadCreditsLines()
    self.assertEqual(expected_lines, credits_lines)

  def testGeneratedLicencesOrder(self):
    # Process files that do not fall into a known bucket and assert that their
    # licenses are listed in alphabetical order of the file names.
    files = [
      'libswresample/swresample.h',
      'libavcodec/arm/jrevdct_arm.S',
      'libavcodec/mips/celp_math_mips.c',
      'libavcodec/mips/acelp_vectors_mips.c',
      'libavformat/oggparsetheora.c',
      'libavcodec/x86/xvididct.asm',
    ]
    updater = NewCreditsUpdater()
    for f in files:
      updater.ProcessFile(f)
    updater.WriteCredits()

    credits = ''.join(ReadCreditsLines())
    current_offset = 0
    for f in sorted(files):
      i = credits.find(f, current_offset)
      if i == -1:
        self.fail("Failed to find %s starting at offset %s of content:\n%s" %
                  (f, current_offset, credits))
      current_offset = i + len(f)


  def testKnownFileDigestChange(self):
    updater = NewCreditsUpdater()

    # Choose a known file.
    known_file = os.path.join('libavformat', 'oggparseogm.c')
    self.assertTrue(known_file in updater.known_file_map)

    # Show file processing works without raising SystemExit.
    updater.ProcessFile(known_file)

    # Alter the license digest for this file to simulate a change to the
    # license header.
    orig_file_info = updater.known_file_map[known_file]
    altered_file_info = cu.FileInfo(cu.License.LGPL,
                                    'chris' + orig_file_info.license_digest[5:])
    updater.known_file_map[known_file] = altered_file_info

    # Verify digest mismatch triggers SystemExit.
    with self.assertRaises(SystemExit):
      updater.ProcessFile(known_file)


# Globals to cache the text of static files once read.
g_license_md_lines = []
g_license_lines = {}


def ReadCreditsLines():
  with open(os.path.join(SOURCE_DIR, OUTPUT_FILE)) as test_credits:
    return test_credits.readlines()


def GetLicenseMdLines():
  global g_license_md_lines
  if not len(g_license_md_lines):
    with open(os.path.join(SOURCE_DIR, cu.UPSTREAM_LICENSEMD)) as license_md:
      g_license_md_lines = license_md.readlines()
  return g_license_md_lines


def GetLicenseLines(license_file):
  if not license_file in g_license_lines:
    g_license_lines[license_file] = GetFileLines(
        os.path.join(cu.LICENSE_TEXTS[license_file]))
  return g_license_lines[license_file]


def GetFileLines(file_path):
  with open(file_path) as open_file:
    return open_file.readlines()


def GetSeparatorLines():
  # Pass True to preserve \n chars in the return.
  return cu.LICENSE_SEPARATOR.splitlines(True)


# Combine into a string then split back out to a list. This is important for
# making constructed expectations match the credits read from a file. E.g.
# input: ['foo', '\n', 'bar']
# return: ['foo\n', 'bar']
# Comparing lists line by line makes for much better diffs when things go wrong.


def NormalizeNewLines(lines):
  return ''.join(lines).splitlines(True)


if __name__ == '__main__':
  unittest.main()
