using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace UnitTestProject1
{
    using Helion;

    [TestClass]
    public class UlamekTesty
    {
        Random r = new Random();

        private int losujLiczbęCałkowitą(int? maksymalnaBezwzględnaWartość = null)
        {
            if (!maksymalnaBezwzględnaWartość.HasValue)
                return r.Next(int.MinValue, int.MaxValue);
            else
                return r.Next(-maksymalnaBezwzględnaWartość.Value, maksymalnaBezwzględnaWartość.Value);
        }

        private int losujLiczbęCałkowitąRóżnąOdZera(int? maksymalnaBezwzględnaWartość = null)
        {
            int wartość;
            do
            {
                wartość = losujLiczbęCałkowitą(maksymalnaBezwzględnaWartość);
            }
            while (wartość == 0);
            return wartość;
        }

        [TestMethod]
        public void TestyKonstruktoraIWłasności()
        {
            //arrange = przygotowanie
            int licznik = losujLiczbęCałkowitą();
            int mianownik = losujLiczbęCałkowitąRóżnąOdZera();

            //act = działanie
            Ulamek u = new Ulamek(licznik, mianownik);

            //assert = weryfikacja
            Assert.AreEqual(licznik, u.Licznik, "Niezgodność w liczniku");
            Assert.AreEqual(mianownik, u.Mianownik, "Niezgodność w mianowniku");
        }

        [TestMethod]
        public void TestKonstruktora()
        {
            //arrange = przygotowanie
            int licznik = losujLiczbęCałkowitą();
            int mianownik = losujLiczbęCałkowitąRóżnąOdZera();

            //act = działanie
            Ulamek u = new Ulamek(licznik, mianownik);

            //assert = weryfikacja
            PrivateObject op = new PrivateObject(u);
            int u_licznik = (int)op.GetField("licznik");
            int u_mianownik = (int)op.GetField("mianownik");
            Assert.AreEqual(licznik, u_licznik, "Niezgodność w liczniku");
            Assert.AreEqual(mianownik, u_mianownik, "Niezgodność w mianowniku");
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void TestKonstruktoraWyjątek()
        {
            int licznik = losujLiczbęCałkowitą();
            Ulamek u = new Ulamek(licznik, 0);
        }

        [TestMethod]
        public void TestPolaPolowa()
        {
            Ulamek uP = Ulamek.Polowa;
            Assert.AreEqual(1, uP.Licznik);
            Assert.AreEqual(2, uP.Mianownik);
        }

        [TestMethod]
        public void TestMetodyUprosc()
        {
            Ulamek u = new Ulamek(4, -2);
            u.Uprosc();
            Assert.AreEqual(-2, u.Licznik);
            Assert.AreEqual(1, u.Mianownik);
        }

        [TestMethod]
        public void TestOperatorówArytmetycznych()
        {
            Ulamek a = Ulamek.Polowa;
            Ulamek b = Ulamek.Cwierc;

            Assert.AreEqual(new Ulamek(3, 4), a + b, "Dodawanie");
            Assert.AreEqual(new Ulamek(1, 4), a - b, "Odejmowanie");
            Assert.AreEqual(new Ulamek(1, 8), a * b, "Mnożenie");
            Assert.AreEqual(new Ulamek(2, 1), a / b, "Dzielenie");
        }

        [TestMethod]
        public void TestSortowania()
        {
            Ulamek[] tablica = new Ulamek[100];
            for (int i = 0; i < tablica.Length; i++)
            {
                tablica[i] = new Ulamek(
                    losujLiczbęCałkowitą(),
                    losujLiczbęCałkowitąRóżnąOdZera());
            }

            Array.Sort(tablica);

            bool tablicaJestPosortowanaRosnąco = true;
            for (int i = 0; i < tablica.Length - 1; i++)
            {
                if (tablica[i] > tablica[i + 1])
                {
                    tablicaJestPosortowanaRosnąco = false;
                    break;
                }
            }
            //Assert.AreEqual(true, tablicaJestPosortowanaRosnąco);
            Assert.IsTrue(tablicaJestPosortowanaRosnąco);
        }

        const int liczbaPowtórzeń = 10000000;

        [TestMethod]
        public void TestKonwersjiDoDouble()
        {
            for (int i = 0; i < liczbaPowtórzeń; ++i)
            {
                int licznik = losujLiczbęCałkowitą();
                int mianownik = losujLiczbęCałkowitąRóżnąOdZera();
                Ulamek u = new Ulamek(licznik, mianownik);

                //double d = u.ToDouble();
                double d = (double)u;

                Assert.AreEqual(licznik / (double)mianownik, d);
            }
        }

        [TestMethod]
        public void TestKonwersjiZInt()
        {
            for (int i = 0; i < liczbaPowtórzeń; ++i)
            {
                int liczba = losujLiczbęCałkowitą();
                
                //Ulamek u = new Ulamek(liczba);
                Ulamek u = liczba;

                Assert.AreEqual(liczba, u.Licznik);
                Assert.AreEqual(1, u.Mianownik);
            }
        }

        [TestMethod]
        public void TestMetodyUprosc2()
        {
            for (int i = 0; i < liczbaPowtórzeń; ++i)
            {
                Ulamek u = new Ulamek(
                    losujLiczbęCałkowitą(),
                    losujLiczbęCałkowitąRóżnąOdZera());
                Ulamek kopia = u; //klonowanie

                u.Uprosc();

                Assert.AreEqual(kopia.ToDouble(), u.ToDouble());
            }
        }

        [TestMethod]
        public void TestOperatorów2()
        {
            int limit = (int)(Math.Sqrt(int.MaxValue/2)-1);
            const double dokładność = 1E-7;

            for (int i = 0; i < liczbaPowtórzeń; ++i)
            {
                Ulamek a = new Ulamek(
                    losujLiczbęCałkowitą(limit),
                    losujLiczbęCałkowitąRóżnąOdZera(limit));
                Ulamek b = new Ulamek(
                    losujLiczbęCałkowitąRóżnąOdZera(limit),
                    losujLiczbęCałkowitąRóżnąOdZera(limit));

                double suma = (a + b).ToDouble();
                double roznica = (a - b).ToDouble();
                double iloczyn = (a * b).ToDouble();
                double iloraz = (a / b).ToDouble();

                Assert.AreEqual(a.ToDouble() + b.ToDouble(), suma, dokładność, "Dodawanie");
                Assert.AreEqual(a.ToDouble() - b.ToDouble(), roznica, dokładność, "Odejmowanie");
                Assert.AreEqual(a.ToDouble() * b.ToDouble(), iloczyn, dokładność, "Mnożenie");
                Assert.AreEqual(a.ToDouble() / b.ToDouble(), iloraz, dokładność, "Dzielenie");
            }
        }
    }
}
