Files
RubyAlgebra/spec/parser_spec.rb
2026-04-13 21:05:59 +03:00

145 lines
5.6 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

require "ruby_algebra"
RSpec.describe RubyAlgebra::Parser do
# Хелпер для быстрой сборки ожидаемых многочленов в тестах
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 'парсит одиночную переменную' 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
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
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 'парсит команду вывода (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("x + 1.0")
expect(interpreter.execute(RubyAlgebra::Parser.parse_command("R"))).to eq("0")
end
end