# frozen_string_literal: true

#
# test/unit/bio/test_sequence.rb - Unit test for Bio::Sequencce
#
# Copyright::  Copyright (C) 2004
#              Moses Hohman <mmhohman@northwestern.edu>
#              2006 Mitsuteru C. Nakao <n@bioruby.org>
# License::    The Ruby License
#
#  $Id:$
#

# loading helper routine for testing bioruby
require 'pathname'
load Pathname.new(File.join(File.dirname(__FILE__), ['..'] * 2,
                            'bioruby_test_helper.rb')).cleanpath.to_s

# libraries needed for the tests
require 'test/unit'
require 'bio/sequence'

module Bio
  class TestSequence < Test::Unit::TestCase
    def setup
      @na  = Sequence::NA.new('atgcatgcatgcatgcaaaa')
      @rna = Sequence::NA.new('augcaugcaugcaugcaaaa')
      @aa  = Sequence::AA.new('ACDEFGHIKLMNPQRSTVWYU')
    end

    # "main" method tests translated into unit tests

    # Test Sequence::NA.new

    def test_DNA_new_blank_sequence
      sequence = Sequence::NA.new('')
      assert_equal(0, sequence.size)
    end

    def test_DNA_new_sequence_downcases_symbols
      string = 'atgcatgcATGCATGCAAAA'
      sequence = Sequence::NA.new(string)
      assert_equal(string.downcase, sequence.to_s)
    end

    def test_RNA_new_sequence
      string = 'augcaugcaugcaugcaaaa'
      sequence = Sequence::NA.new(string)
      assert_equal(string, sequence.to_s)
    end

    # added

    def test_DNA_new_sequence_removes_whitespace
      sequence = Sequence::NA.new("a g\tc\nt\ra")
      assert_equal('agcta', sequence)
    end

    # Test Sequence::AA.new

    def test_AA_new_blank_sequence
      sequence = Sequence::AA.new('')
      assert_equal(0, sequence.size)
    end

    def test_AA_new_sequence_all_legal_symbols
      string = 'ACDEFGHIKLMNPQRSTVWYU'
      sequence = Sequence::AA.new(string)
      assert_equal(string, sequence.to_s)
    end

    # added

    def test_AA_new_sequence_upcases_symbols
      string = 'upcase'
      sequence = Sequence::AA.new(string)
      assert_equal(string.upcase, sequence.to_s)
    end

    def test_AA_new_sequence_removes_whitespace
      sequence = Sequence::AA.new("S T\tR\nI\rP")
      assert_equal('STRIP', sequence)
    end

    # test element indexing

    def test_element_reference_operator_with_two_arguments
      sequence = Sequence::NA.new('atggggggtc')
      assert_equal('gggggg', sequence[2, 6])
    end

    # added
    def test_element_reference_operator_with_one_argument
      sequence = Sequence::NA.new('atggggggtc')
      assert_equal('t', sequence[1])
    end

    # Test Sequence#total

    def test_total
      sequence = Sequence::NA.new('catccagtccctggt')
      assert_equal(2346, sequence.total({ 'a' => 1000, 'g' => 100, 't' => 10, 'c' => 1 }))
    end

    # Test Sequence#composition

    def test_dna_composition
      sequence = Sequence::NA.new('aggtttcccc')
      expected = { 'a' => 1, 'g' => 2, 't' => 3, 'c' => 4 }
      expected.default = 0
      assert_equal(expected, sequence.composition)
    end

    def test_rna_composition
      sequence = Sequence::NA.new('agguuucccc')
      expected = { 'a' => 1, 'g' => 2, 'u' => 3, 'c' => 4 }
      expected.default = 0
      assert_equal(expected, sequence.composition)
    end

    # I don't get splicing

    # Test Sequence::NA#complement

    def test_dna_sequence_complement
      assert_equal('ttttgcatgcatgcatgcat', @na.complement)
    end

    def test_rna_sequence_complement
      assert_equal('uuuugcaugcaugcaugcau', @rna.complement)
    end

    def test_ambiguous_dna_sequence_complement
      assert_equal('nwsbvhdkmyrcgta', Sequence::NA.new('tacgyrkmhdbvswn').complement)
    end

    def test_ambiguous_rna_sequence_complement
      assert_equal('nwsbvhdkmyrcgua', Sequence::NA.new('uacgyrkmhdbvswn').complement)
    end

    # Test Sequence::NA#translate

    def test_dna_sequence_translate
      assert_equal('MHACMQ', @na.translate)
    end

    def test_rna_sequence_translate
      assert_equal('MHACMQ', @rna.translate)
    end

    # Test Sequence::NA#gc_percent

    def test_dna_gc_percent
      assert_equal(40, @na.gc_percent)
    end

    def test_rna_gc_percent
      assert_equal(40, @rna.gc_percent)
    end

    # Test Sequence::NA#illegal_bases

    def test_valid_dna_sequence_illegal_bases
      assert_equal([], @na.illegal_bases)
    end

    def test_invalid_nucleic_acid_illegal_bases
      string = 'tacgyrkmhdbvswn'
      expected = []
      string[4..-1].each_byte { |val| expected << val.chr }
      assert_equal(expected.sort, Sequence::NA.new(string).illegal_bases)
    end

    def test_invalid_nucleic_acid_illegal_bases_more
      string = 'abcdefghijklmnopqrstuvwxyz-!%#$@'
      expected = []
      'bdefhijklmnopqrsvwxyz-!%#$@'.each_byte { |val| expected << val.chr }
      assert_equal(expected.sort, Sequence::NA.new(string).illegal_bases)
    end

    # Test Sequence::NA#molecular_weight

    def test_dna_molecular_weight
      assert_in_delta(6174.3974, @na.molecular_weight, 1e-5)
    end

    def test_rna_molecular_weight
      assert_in_delta(6438.2774, @rna.molecular_weight, 1e-5)
    end

    # Test Sequence::NA#to_re

    def test_dna_to_re
      assert_equal(/atgc[agr][tcy][acm][tgk][atgrwkd][atcwmyh][agcmrsv][tgcyskb][gcs][atw][atgcyrwskmbdhvn]/, Sequence::NA.new('atgcrymkdhvbswn').to_re)
    end

    def test_rna_to_re
      assert_equal(/augc[agr][ucy][acm][ugk][augrwkd][aucwmyh][agcmrsv][ugcyskb][gcs][auw][augcyrwskmbdhvn]/, Sequence::NA.new('augcrymkdhvbswn').to_re)
    end

    # Test Sequence::NA#names

    def test_nucleic_acid_names
      # It is a Bio::NucleicAcid feature.
      #      assert_equal(["adenine", "cytosine", "guanine", "thymine", "uracil"], Sequence::NA.new('acgtu').names)
      assert(Sequence::NA.new('acgtu').names)
    end

    # Test Sequence::NA#pikachu

    def test_dna_pikachu
      assert_equal('pika', Sequence::NA.new('atgc').pikachu)
    end

    def test_rna_pikachu
      assert_equal('pika', Sequence::NA.new('augc').pikachu)
    end

    # Test Sequence::NA#randomize

    def test_randomize_dna_retains_composition
      assert_equal(@na.composition, @na.randomize.composition)
    end

    # this test has a neglibly small chance of failure
    def test_two_consecutive_dna_randomizations_not_equal
      assert_not_equal(@na.randomize, @na.randomize)
    end

    def test_randomize_dna_can_be_chained
      assert_equal(@na.composition, @na.randomize.randomize.composition)
    end

    def test_randomize_dna_with_block
      appended = String.new
      @na.randomize { |x| appended << x }
      assert_equal(@na.composition, Sequence::NA.new(appended).composition)
    end

    # Test Sequence::NA.randomize(counts)

    def test_NA_randomize_with_counts
      counts = { 'a' => 10, 'c' => 20, 'g' => 30, 'u' => 40 }
      counts.default = 0
      assert_equal(counts, Sequence::NA.randomize(counts).composition)
    end

    def test_NA_randomize_with_counts_and_block
      appended = String.new
      counts = { 'a' => 10, 'c' => 20, 'g' => 30, 'u' => 40 }
      counts.default = 0
      Sequence::NA.randomize(counts) { |x| appended << x }
      assert_equal(counts, Sequence::NA.new(appended).composition)
    end

    # Test Sequence::AA#codes

    def test_amino_acid_codes
      assert_equal(%w[Ala Cys Asp Glu Phe Gly His Ile Lys
                      Leu Met Asn Pro Gln Arg Ser Thr Val Trp
                      Tyr Sec], @aa.codes)
    end

    # Test Sequence::AA#names

    def test_amino_acid_names
      assert_equal(['alanine', 'cysteine', 'aspartic acid', 'glutamic acid', 'phenylalanine',
                    'glycine', 'histidine', 'isoleucine', 'lysine', 'leucine', 'methionine',
                    'asparagine', 'proline', 'glutamine', 'arginine', 'serine', 'threonine',
                    'valine', 'tryptophan', 'tyrosine', 'selenocysteine'], @aa.names)
    end

    # Test Sequence::AA#molecular_weight

    def test_amino_acid_molecular_weight
      assert_in_delta(2395.725, @aa.subseq(1, 20).molecular_weight, 0.0001)
    end

    # Test Sequence::AA#randomize

    def test_amino_acid_randomize_has_same_composition
      aaseq = 'MRVLKFGGTSVANAERFLRVADILESNARQGQVATVLSAPAKITNHLVAMIEKTISGQDA'
      s = Sequence::AA.new(aaseq)
      assert_equal(s.composition, s.randomize.composition)
    end

    # this test has a neglibly small chance of failure
    def test_consecutive_amino_acid_randomizes_are_not_equal
      aaseq = 'MRVLKFGGTSVANAERFLRVADILESNARQGQVATVLSAPAKITNHLVAMIEKTISGQDA'
      s = Sequence::AA.new(aaseq)
      assert_not_equal(s.randomize, s.randomize)
    end

    def test_amino_acid_randomize_can_be_chained
      aaseq = 'MRVLKFGGTSVANAERFLRVADILESNARQGQVATVLSAPAKITNHLVAMIEKTISGQDA'
      s = Sequence::AA.new(aaseq)
      assert_equal(s.randomize.composition, s.randomize.randomize.composition)
    end
  end

  class TestNATranslate < Test::Unit::TestCase
    def setup
      @obj = Bio::Sequence::NA.new('AAA')
    end

    def test_translate
      assert_equal('K', @obj.translate)
    end

    def test_translate_1
      assert_equal('K', @obj.translate(1))
    end

    def test_translate_2
      assert_equal('', @obj.translate(2))
    end

    def test_translate_3
      assert_equal('', @obj.translate(3))
    end

    def test_translate_4
      assert_equal('F', @obj.translate(4))
    end

    def test_translate_5
      assert_equal('', @obj.translate(5))
    end

    def test_translate_6
      assert_equal('', @obj.translate(6))
    end
  end
end
