Загрузка данных


using NUnit.Framework;
using lab3.transport;

namespace lab3.tests
{
    [TestFixture]
    public class TaxiTests
    {
        // 6. Такси: выручка = цена/км × км × пассажиры
        [Test]
        public void Taxi_CalculatesRevenueByDistanceAndPassengers()
        {
            var taxi = new Taxi(costPerKm: 20, totalKm: 15);

            for (int i = 0; i < 4; i++) taxi.AddPassenger(false);

            // 20 × 15 × 4 = 1200
            Assert.That(taxi.CalculateRevenue(), Is.EqualTo(1200.0));
        }

        // 7. Такси игнорирует льготный флаг (у такси нет льготных билетов)
        [Test]
        public void Taxi_BenefitFlag_DoesNotAffectRevenue()
        {
            var taxi = new Taxi(costPerKm: 20, totalKm: 10);

            taxi.AddPassenger(false);   // обычный
            taxi.AddPassenger(true);    // «льготник» — но формула одна

            // 20 × 10 × 2 = 400, независимо от флагов
            Assert.That(taxi.CalculateRevenue(), Is.EqualTo(400.0));
        }
    }
}

using NUnit.Framework;
using lab3.transport.public_transport;

namespace lab3.tests
{
    [TestFixture]
    public class FareTransportTests
    {
        // 1. Автобус: смешанные пассажиры — формула выручки
        [Test]
        public void Bus_WithMixedPassengers_CalculatesRevenueCorrectly()
        {
            // Arrange
            var bus = new Bus(generalTicketCost: 30, benefitTicketCost: 15, routeNumber: "12");

            // Act
            for (int i = 0; i < 10; i++) bus.AddPassenger(false);
            for (int i = 0; i < 3; i++) bus.AddPassenger(true);

            // Assert
            // (10 × 30) + (3 × 15) = 300 + 45 = 345
            Assert.That(bus.CalculateRevenue(), Is.EqualTo(345.0));
        }

        // 2. Автобус без пассажиров — выручка равна нулю
        [Test]
        public void Bus_WithoutPassengers_ReturnsZeroRevenue()
        {
            var bus = new Bus(30, 15, "12");

            Assert.That(bus.CalculateRevenue(), Is.EqualTo(0.0));
        }

        // 3. Автобус только со льготниками — используется льготный тариф
        [Test]
        public void Bus_OnlyBenefitPassengers_UsesBenefitTicketCost()
        {
            var bus = new Bus(generalTicketCost: 30, benefitTicketCost: 15, routeNumber: "12");

            for (int i = 0; i < 5; i++) bus.AddPassenger(true);

            // 5 × 15 = 75
            Assert.That(bus.CalculateRevenue(), Is.EqualTo(75.0));
        }

        // 4. Счётчики пассажиров: обычные и льготники разделены
        [Test]
        public void PassengerCounters_TrackRegularAndBenefitSeparately()
        {
            var tram = new Tram(25, 12, "4");

            for (int i = 0; i < 7; i++) tram.AddPassenger(false);
            for (int i = 0; i < 3; i++) tram.AddPassenger(true);

            Assert.Multiple(() =>
            {
                Assert.That(tram.PassengerCount, Is.EqualTo(10));
                Assert.That(tram.BenefitPassengerCount, Is.EqualTo(3));
            });
        }

        // 5. Параметризованный тест для разных видов «билетного» транспорта:
        //    у всех формула одинаковая, отличаются лишь цены
        [TestCase(30, 15, 10, 3, 345.0)]   // Bus
        [TestCase(25, 12, 8, 2, 224.0)]   // Tram
        [TestCase(28, 14, 6, 1, 182.0)]   // Trolleybus
        [TestCase(150, 75, 50, 10, 8250.0)] // Train
        public void FareTransport_RevenueFormula_IsUniform(
            int general, int benefit, int regularCount, int benefitCount, double expected)
        {
            var bus = new Bus(general, benefit, "test");

            for (int i = 0; i < regularCount; i++) bus.AddPassenger(false);
            for (int i = 0; i < benefitCount; i++) bus.AddPassenger(true);

            Assert.That(bus.CalculateRevenue(), Is.EqualTo(expected));
        }
    }
}

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.10.1" />
    <PackageReference Include="NUnit" Version="5.0.0" />
    <PackageReference Include="NUnit3TestAdapter" Version="6.3.0" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\lab3\lab3.csproj" />
  </ItemGroup>

</Project>

using NUnit.Framework;
using lab3.transport.public_transport;

namespace lab3.tests
{
    [TestFixture]
    public class MinibusTests
    {
        // 8. Маршрутка: не пускает пассажиров сверх вместимости
        [Test]
        public void Minibus_DoesNotExceedCapacity()
        {
            var minibus = new Minibus(
                generalTicketCost: 40,
                benefitTicketCost: 20,
                routeNumber: "45",
                capacity: 3);

            for (int i = 0; i < 5; i++) minibus.AddPassenger(false);

            Assert.That(minibus.PassengerCount, Is.EqualTo(3));
        }

        // 9. Маршрутка: IsFull становится true при достижении вместимости
        [Test]
        public void Minibus_IsFull_ReturnsTrueWhenAtCapacity()
        {
            var minibus = new Minibus(40, 20, "45", capacity: 2);

            Assert.That(minibus.IsFull, Is.False);

            minibus.AddPassenger(false);
            minibus.AddPassenger(true);

            Assert.Multiple(() =>
            {
                Assert.That(minibus.IsFull, Is.True);
                Assert.That(minibus.PassengerCount, Is.EqualTo(2));
                Assert.That(minibus.BenefitPassengerCount, Is.EqualTo(1));
            });
        }
    }
}

namespace lab3.transport
{
    public abstract class FareTransport : PassengerTransport
    {
        protected readonly int _generalTicketCost;
        protected readonly int _benefitTicketCost;

        protected FareTransport(int generalTicketCost, int benefitTicketCost)
        {
            _generalTicketCost = generalTicketCost;
            _benefitTicketCost = benefitTicketCost;
        }

        public override double CalculateRevenue()
        {
            return (PassengerCount - BenefitPassengerCount) * _generalTicketCost
                 + BenefitPassengerCount * _benefitTicketCost;
        }
    }
}

namespace lab3.transport
{
    public abstract class PassengerTransport : Transport, IPassengerCarrier
    {
        public int PassengerCount { get; protected set; }
        public int BenefitPassengerCount { get; protected set; }

        public virtual void AddPassenger(bool hasBenefit)
        {
            PassengerCount += 1;
            if (hasBenefit)
                BenefitPassengerCount += 1;
        }
    }
}

namespace lab3.transport
{
    public sealed class Taxi : PassengerTransport
    {
        public int CostPerKm { get; }
        private readonly int _totalKm;

        public Taxi(int costPerKm, int totalKm)
        {
            CostPerKm = costPerKm;
            _totalKm = totalKm;
        }

        public override double CalculateRevenue()
        {
            return CostPerKm * _totalKm * PassengerCount;
        }
    }
}

namespace lab3.transport.public_transport
{
    public sealed class Bus : FareTransport, IRouteBased
    {
        public string RouteNumber { get; }

        public Bus(int generalTicketCost, int benefitTicketCost, string routeNumber)
            : base(generalTicketCost, benefitTicketCost)
        {
            RouteNumber = routeNumber;
        }
    }
}

namespace lab3.transport.public_transport
{
    public sealed class Minibus : FareTransport, IRouteBased, ICapacityLimited
    {
        public string RouteNumber { get; }
        public int Capacity { get; }
        public bool IsFull => PassengerCount >= Capacity;

        public Minibus(int generalTicketCost, int benefitTicketCost,
                       string routeNumber, int capacity)
            : base(generalTicketCost, benefitTicketCost)
        {
            RouteNumber = routeNumber;
            Capacity = capacity;
        }

        public override void AddPassenger(bool hasBenefit)
        {
            if (IsFull)
                return;    // переопределение базового поведения

            base.AddPassenger(hasBenefit);
        }
    }
}

namespace lab3.transport.public_transport
{
    public sealed class Train : FareTransport, IRouteBased
    {
        public string RouteNumber { get; }

        public Train(int generalTicketCost, int benefitTicketCost, string routeNumber)
            : base(generalTicketCost, benefitTicketCost)
        {
            RouteNumber = routeNumber;
        }
    }
}

namespace lab3.transport.public_transport
{
    public sealed class Tram : FareTransport, IRouteBased
    {
        public string RouteNumber { get; }

        public Tram(int generalTicketCost, int benefitTicketCost, string routeNumber)
            : base(generalTicketCost, benefitTicketCost)
        {
            RouteNumber = routeNumber;
        }
    }
}

namespace lab3.transport.public_transport
{
    public sealed class Trolleybus : FareTransport, IRouteBased
    {
        public string RouteNumber { get; }

        public Trolleybus(int generalTicketCost, int benefitTicketCost, string routeNumber)
            : base(generalTicketCost, benefitTicketCost)
        {
            RouteNumber = routeNumber;
        }
    }
}

namespace lab3
{
    public interface ICapacityLimited
    {
        int Capacity { get; }
        bool IsFull { get; }
    }
}

namespace lab3
{
    public interface IPassengerCarrier
    {
        int PassengerCount { get; }
        int BenefitPassengerCount { get; }
        void AddPassenger(bool hasBenefit);
    }
}

namespace lab3
{
    public interface IRevenueCalculatable
    {
        double CalculateRevenue();
    }
}

namespace lab3
{
    public interface IRouteBased
    {
        string RouteNumber { get; }
    }
}

using lab3.transport;
using lab3.transport.public_transport;

namespace lab3
{
    internal class Program
    {
        static void Main()
        {
            Console.WriteLine("=== Демонстрация работы транспорта ===\n");

            // --- Такси: тариф за км, льгот нет ---
            var taxi = new Taxi(costPerKm: 25, totalKm: 40);
            taxi.AddPassenger(false);
            taxi.AddPassenger(false);
            taxi.AddPassenger(true);
            Console.WriteLine($"Такси: пассажиров = {taxi.PassengerCount}, " +
                              $"из них льготных = {taxi.BenefitPassengerCount}, " +
                              $"выручка = {taxi.CalculateRevenue():F2}");

            // --- Автобус: фиксированная стоимость билета ---
            var bus = new Bus(generalTicketCost: 50, benefitTicketCost: 25, routeNumber: "12A");
            bus.AddPassenger(false);
            bus.AddPassenger(true);
            bus.AddPassenger(false);
            bus.AddPassenger(true);
            Console.WriteLine($"Автобус (маршрут {bus.RouteNumber}): " +
                              $"пассажиров = {bus.PassengerCount}, " +
                              $"льготных = {bus.BenefitPassengerCount}, " +
                              $"выручка = {bus.CalculateRevenue():F2}");

            // --- Маршрутка: ограниченная вместимость ---
            var minibus = new Minibus(generalTicketCost: 40, benefitTicketCost: 20,
                                      routeNumber: "8", capacity: 3);
            for (int i = 0; i < 5; i++)
                minibus.AddPassenger(i % 2 == 0);   // 5 попыток, но влезет только 3
            Console.WriteLine($"Маршрутка (маршрут {minibus.RouteNumber}): " +
                              $"вместимость = {minibus.Capacity}, " +
                              $"пассажиров = {minibus.PassengerCount}, " +
                              $"заполнена = {minibus.IsFull}, " +
                              $"выручка = {minibus.CalculateRevenue():F2}");

            // --- Трамвай ---
            var tram = new Tram(generalTicketCost: 30, benefitTicketCost: 15, routeNumber: "5");
            tram.AddPassenger(false);
            tram.AddPassenger(true);
            tram.AddPassenger(true);
            Console.WriteLine($"Трамвай (маршрут {tram.RouteNumber}): " +
                              $"пассажиров = {tram.PassengerCount}, " +
                              $"выручка = {tram.CalculateRevenue():F2}");

            // --- Троллейбус ---
            var trolleybus = new Trolleybus(generalTicketCost: 35, benefitTicketCost: 17,
                                            routeNumber: "7");
            trolleybus.AddPassenger(false);
            trolleybus.AddPassenger(false);
            Console.WriteLine($"Троллейбус (маршрут {trolleybus.RouteNumber}): " +
                              $"выручка = {trolleybus.CalculateRevenue():F2}");

            // --- Поезд ---
            var train = new Train(generalTicketCost: 100, benefitTicketCost: 50,
                                  routeNumber: "Электричка 6001");
            for (int i = 0; i < 10; i++) train.AddPassenger(false);
            train.AddPassenger(true);
            train.AddPassenger(true);
            Console.WriteLine($"Поезд (маршрут {train.RouteNumber}): " +
                              $"пассажиров = {train.PassengerCount}, " +
                              $"выручка = {train.CalculateRevenue():F2}");

            // --- Полиморфная обработка списка через базовый класс Transport ---
            Console.WriteLine("\n=== Полиморфная обработка списка транспорта ===");
            var transports = new List<Transport>
            {
                taxi, bus, minibus, tram, trolleybus, train
            };

            double totalRevenue = 0;
            foreach (var t in transports)
            {
                double revenue = t.CalculateRevenue();
                totalRevenue += revenue;
                string info = t is IRouteBased rb ? $"маршрут {rb.RouteNumber}" : "без маршрута";
                Console.WriteLine($"{t.GetType().Name,-12} {info,-25} выручка = {revenue,10:F2}");
            }
            Console.WriteLine($"\nОбщая выручка: {totalRevenue:F2}");

            // --- Работа с интерфейсами через приведение типов ---
            Console.WriteLine("\n=== ICapacityLimited ===");
            foreach (var t in transports)
                if (t is ICapacityLimited cl)
                    Console.WriteLine($"  {t.GetType().Name}: вместимость = {cl.Capacity}, " +
                                      $"заполнен = {cl.IsFull}");

            Console.WriteLine("\n=== IRouteBased ===");
            foreach (var t in transports)
                if (t is IRouteBased r)
                    Console.WriteLine($"  {t.GetType().Name}: маршрут = {r.RouteNumber}");

            Console.WriteLine("\n=== IPassengerCarrier ===");
            foreach (var t in transports)
                if (t is IPassengerCarrier pc)
                    Console.WriteLine($"  {t.GetType().Name}: пассажиров = {pc.PassengerCount}, " +
                                      $"льготных = {pc.BenefitPassengerCount}");

            // --- Сортировка по выручке (используем IRevenueCalculatable полиморфно) ---
            Console.WriteLine("\n=== Транспорт, отсортированный по выручке (по убыванию) ===");
            var sorted = new List<Transport>(transports);
            sorted.Sort((a, b) => b.CalculateRevenue().CompareTo(a.CalculateRevenue()));
            foreach (var t in sorted)
                Console.WriteLine($"  {t.GetType().Name,-12} = {t.CalculateRevenue(),10:F2}");
        }
    }
}

namespace lab3
{
    public abstract class Transport : IRevenueCalculatable
    {
        public abstract double CalculateRevenue();
    }
}