From 2890087e367c2a1762470912d8169ea4de90290f Mon Sep 17 00:00:00 2001 From: Chernykh Aleksandr Date: Mon, 13 Apr 2026 20:29:46 +0300 Subject: [PATCH] tests --- spec/parser_spec.rb | 181 +++++++++++++++++++++++++++++++------------- 1 file changed, 129 insertions(+), 52 deletions(-) diff --git a/spec/parser_spec.rb b/spec/parser_spec.rb index 78fe31a..d288322 100644 --- a/spec/parser_spec.rb +++ b/spec/parser_spec.rb @@ -1,67 +1,144 @@ require "ruby_algebra" - -RSpec.configure do |config| - config.expect_with :rspec do |expectations| - expectations.include_chain_clauses_in_custom_matcher_descriptions = true - end -end - RSpec.describe RubyAlgebra::Parser do - describe "#parse" do - it "returns nil for an empty string" do - expect(RubyAlgebra::Parser.parse("")).to eq nil + # Хелпер для быстрой сборки ожидаемых многочленов в тестах + def build_poly(terms_array) + terms = terms_array.map do |t| + RubyAlgebra::Term.new(t[:coeff], t[:vars] || {}) + end + RubyAlgebra::Polynomial.new(terms) + end + + describe '.parse_polynomial' do + let(:tokenizer) { ->(str) { RubyAlgebra::Parser::Tokenizer.new(str) } } + + it 'парсит простое число как константный многочлен' do + result = RubyAlgebra::Parser.parse_polynomial(tokenizer.call("42")) + expect(result).to eq(build_poly([{ coeff: 42 }])) end - it "returns Constant(a) for a" do - [10, 100, 343843, 180.1, 777, 0.52242].each do |a| - expect(RubyAlgebra::Parser.parse(a.to_s)).to eq RubyAlgebra::Constant.new(a) + it 'парсит одиночную переменную' do + result = RubyAlgebra::Parser.parse_polynomial(tokenizer.call("x")) + expect(result).to eq(build_poly([{ coeff: 1, vars: { "x" => 1 } }])) + end + + it 'парсит многочлен с несколькими термами и степенями' do + # 2x^2 + 3x - 5 + result = RubyAlgebra::Parser.parse_polynomial(tokenizer.call("2x^2 + 3x - 5")) + expected = build_poly([ + { coeff: 2, vars: { "x" => 2 } }, + { coeff: 3, vars: { "x" => 1 } }, + { coeff: -5, vars: {} } + ]) + expect(result).to eq(expected) + end + + it 'обрабатывает отрицательный первый терм' do + result = RubyAlgebra::Parser.parse_polynomial(tokenizer.call("-x + 1")) + expect(result).to eq(build_poly([ + { coeff: -1, vars: { "x" => 1 } }, + { coeff: 1 } + ])) + end + end + + describe '.parse_command' do + context 'Арифметические операции (взаимодействие многочленов)' do + it 'парсит команду сложения: C := A + B' do + cmd = RubyAlgebra::Parser.parse_command("C := A + B") + expect(cmd).to be_a(RubyAlgebra::AssignmentCommand) + expect(cmd.operation).to eq(:add) + expect(cmd.lhs).to eq("C") + expect(cmd.operand1).to eq("A") + expect(cmd.operand2).to eq("B") + end + + it 'парсит команду вычитания: Result := P1 - P2' do + cmd = RubyAlgebra::Parser.parse_command("Result := P1 - P2") + expect(cmd.operation).to eq(:sub) + expect(cmd.operand1).to eq("P1") + expect(cmd.operand2).to eq("P2") + end + + it 'парсит команду умножения: M := Poly1 * Poly2' do + cmd = RubyAlgebra::Parser.parse_command("M := Poly1 * Poly2") + expect(cmd.operation).to eq(:mult) + expect(cmd.operand1).to eq("Poly1") + expect(cmd.operand2).to eq("Poly2") + end + + it 'парсит деление с остатком: Q, R := A / B' do + cmd = RubyAlgebra::Parser.parse_command("Q, R := A / B") + expect(cmd.operation).to eq(:div) + expect(cmd.lhs).to eq(["Q", "R"]) + expect(cmd.operand1).to eq("A") + expect(cmd.operand2).to eq("B") end end - it "returns Variable(x) for x" do - ["x", "y", "z", "coolVariable"].each do |x| - expect(RubyAlgebra::Parser.parse(x)).to eq RubyAlgebra::Variable.new(x) + context 'Операции с числами (Scales)' do + it 'парсит умножение на число как :scale' do + cmd = RubyAlgebra::Parser.parse_command("A := B * 10") + expect(cmd.operation).to eq(:scale) + expect(cmd.operand2).to eq(10) + end + + it 'парсит деление на число как :scale с инверсией' do + cmd = RubyAlgebra::Parser.parse_command("A := B / 2") + expect(cmd.operation).to eq(:scale) + expect(cmd.operand2).to eq(0.5) end end - it "returns Addition(Constant(5), Variable(x)) for 5 + x" do - expect(RubyAlgebra::Parser.parse("5 + x")).to eq RubyAlgebra::Addition.new(RubyAlgebra::Constant.new(5), RubyAlgebra::Variable.new("x")) + context 'Специальные методы' do + it 'парсит дифференцирование: D := Diff(P, x)' do + cmd = RubyAlgebra::Parser.parse_command("D := Diff(P, x)") + expect(cmd.operation).to eq(:diff) + expect(cmd.operand1).to eq("P") + expect(cmd.operand2).to eq(["x"]) + end + + it 'парсит подстановку: S := Subs(P, x=2, y=3)' do + cmd = RubyAlgebra::Parser.parse_command("S := Subs(P, x=2, y=3)") + expect(cmd.operation).to eq(:subs) + expect(cmd.operand1).to eq("P") + expect(cmd.operand2).to eq({ "x" => 2, "y" => 3 }) + end end - it "returns Subtraction(Variable(z), Variable(h)) for z - h" do - expect(RubyAlgebra::Parser.parse("z - h")).to eq RubyAlgebra::Subtraction.new(RubyAlgebra::Variable.new("z"), RubyAlgebra::Variable.new("h")) - end - - it "returns Multiplication(Constant(5), Constant(8)) for 60 * 8" do - expect(RubyAlgebra::Parser.parse("60 * 8")).to eq RubyAlgebra::Multiplication.new(RubyAlgebra::Constant.new(60), RubyAlgebra::Constant.new(8)) - end - - it "returns Division(Constant(3), Variable(j)) for 3/j" do - expect(RubyAlgebra::Parser.parse("3/j")).to eq RubyAlgebra::Division.new(RubyAlgebra::Constant.new(3), RubyAlgebra::Variable.new("j")) - end - - it "returns Division(Constant(3), Variable(j)) for 3/j" do - expect(RubyAlgebra::Parser.parse("3/j")).to eq RubyAlgebra::Division.new(RubyAlgebra::Constant.new(3), RubyAlgebra::Variable.new("j")) - end - - it "returns Power(Constant(2), Constant(24)) for 2^24" do - expect(RubyAlgebra::Parser.parse("2^24")).to eq RubyAlgebra::Power.new(RubyAlgebra::Constant.new(2), RubyAlgebra::Constant.new(24)) - end - - it "returns Multiplication(Constant(-1), Variable(x)) for -x" do - expect(RubyAlgebra::Parser.parse("-x")).to eq RubyAlgebra::Multiplication.new(RubyAlgebra::Constant.new(-1), RubyAlgebra::Variable.new("x")) - end - - it "returns Variable(x) for +x" do - expect(RubyAlgebra::Parser.parse("x")).to eq RubyAlgebra::Variable.new("x") - end - - it "returns Addition(Addition(Constant(3), Constant(30)), Constant(300)) for 3 + 30 + 300" do - expect(RubyAlgebra::Parser.parse("3 + 30 + 300")).to eq RubyAlgebra::Addition.new(RubyAlgebra::Addition.new(RubyAlgebra::Constant.new(3), RubyAlgebra::Constant.new(30)), RubyAlgebra::Constant.new(300)) - end - - it "returns Power(Constant(10), Power(Constant(10), Constant(10))) for 10 ^ 10 ^ 10" do - expect(RubyAlgebra::Parser.parse("10 ^ 10 ^ 10")).to eq RubyAlgebra::Power.new(RubyAlgebra::Constant.new(10), RubyAlgebra::Power.new(RubyAlgebra::Constant.new(10), RubyAlgebra::Constant.new(10))) + it 'парсит команду вывода (Display)' do + cmd = RubyAlgebra::Parser.parse_command("A") + expect(cmd).to be_a(RubyAlgebra::DisplayCommand) + expect(cmd.item).to eq("A") end end end + +RSpec.describe RubyAlgebra::Interpreter do + let(:interpreter) { RubyAlgebra::Interpreter.new } + + it 'выполняет цепочку: присваивание и сложение' do + # Создаем полиномы через парсер и выполняем команды через интерпретатор + p1_cmd = RubyAlgebra::Parser.parse_command("A := 2x") + p2_cmd = RubyAlgebra::Parser.parse_command("B := 3x + 1") + add_cmd = RubyAlgebra::Parser.parse_command("C := A + B") + + interpreter.execute(p1_cmd) + interpreter.execute(p2_cmd) + result_str = interpreter.execute(add_cmd) + + expect(result_str).to include("5x + 1") + end + + it 'выполняет деление с остатком' do + # (x^2 - 1) / (x - 1) = x + 1, остаток 0 + interpreter.execute(RubyAlgebra::Parser.parse_command("A := 1x^2 - 1")) + interpreter.execute(RubyAlgebra::Parser.parse_command("B := 1x - 1")) + + # В вашей грамматике деление: Q, R := A / B + cmd = RubyAlgebra::Parser.parse_command("Q, R := A / B") + interpreter.execute(cmd) + + expect(interpreter.execute(RubyAlgebra::Parser.parse_command("Q"))).to eq("1.0x + 1.0") + expect(interpreter.execute(RubyAlgebra::Parser.parse_command("R"))).to eq("0") + end +end