$:.unshift File.dirname(__FILE__) + '/../lib'
require 'mint'
+Spec::Matchers.define :have_certain_param do |name, value|
+ match do |object|
+ object.instance_variable_get(name) == value
+ end
+end
+
+shared_examples_for 'generator' do
+ it do
+ subject.should_receive(:setup).
+ exactly(1).times.with(no_args)
+ subject.should_receive(:generate_problem).
+ exactly(1).times.and_return('problem')
+ subject.should_receive(:teardown).
+ exactly(1).times.with('problem')
+ subject.generate.should have(1).problems
+ end
+
+ context 'options' do
+
+ before do
+ @options = { :range => (5..10) }
+ @defaults = [
+ [:test1, 'test1'],
+ [:test2, 'test2'],
+ [:test3, 'test3'],
+ ]
+
+ klass = subject.class
+ klass.__send__(:option, *@defaults[0])
+ klass.__send__(:option, *@defaults[1])
+ klass.__send__(:option, *@defaults[2])
+
+ subject.__send__(:options=, @options)
+ end
+
+ context 'set defaults' do
+ before { @default_options = subject.class.__send__(:class_variable_get, :@@default_options) }
+ it { @default_options.should include(*@defaults.map(&:first)) }
+ end
+
+ context 'refer' do
+ before { @opts = subject.__send__(:options) }
+ it { @opts.should include(:range) }
+ it { @opts.should include(:test1) }
+ it { @opts.should include(:test2) }
+ it { @opts.should include(:test3) }
+ it { @opts[:range].should == @options[:range] }
+ it { @opts[:test1].should == @defaults.assoc(:test1)[1] }
+ it { @opts[:test2].should == @defaults.assoc(:test2)[1] }
+ it { @opts[:test3].should == @defaults.assoc(:test3)[1] }
+ end
+ end
+end
+
+shared_examples_for 'Arithmetic' do
+
+ def set_options(options = {})
+ defaults = {:term_number => 1, :operators => ['@']}
+ subject.__send__(:options=, defaults.merge(options))
+ end
+
+ before { set_options }
+
+ it_should_behave_like 'generator'
+
+ [
+ [' -25', ' (-25)'],
+ ['-25', '-25'],
+ [' 25', ' 25'],
+ [' -25', ' (-25)'],
+
+ ].each do |from, to|
+ it do
+ subject.__send__(:teardown, from).should == to
+ end
+ end
+
+ [
+ [:factor, 5],
+ [:spec, 10],
+ [:hoge, 12],
+ [:zero, 0],
+
+ ].each do |position, term_number|
+ context position do
+ before do
+ options = {
+ :"#{position}_term_min" => term_number,
+ :"#{position}_term_max" => term_number,
+ }
+ subject.stub(:options => options)
+ end
+ it { subject.__send__(:term_number, position).should == term_number }
+ end
+ end
+
+ context 'generate problem' do
+
+ before(:all) do
+ subject.class.
+ __send__(:define_method, :generate_problem) do
+ expression
+ end
+ end
+
+ before { subject.should_receive(:expression) }
+
+ it('generate') { subject.generate }
+ it('generate_problem') { subject.__send__(:generate_problem) }
+
+ it 'can set options' do
+ options = { :a => 'a', :b => 'b' }
+ subject.generate(options)
+ subject.instance_variable_get(:@options).
+ should include(:a, :b)
+ end
+ end
+
+ context 'create expression' do
+
+ (1..10).each do |i|
+
+ it "call x #{i}" do
+ set_options(:term_number => i)
+ subject.should_receive(:operand).exactly(i)
+ subject.should_receive(:last_operand).exactly(i)
+ subject.should_receive(:last_operator).exactly(i)
+ subject.__send__(:expression)
+ end
+
+ it "@ x #{i-1}" do
+ set_options(:term_number => i)
+ generator = subject.dup
+ def generator.operand; 'operand' end
+ generator.__send__(:expression).scan('@').should have(i-1).operators
+ end
+ end
+ end
+
+ context 'operand' do
+
+ before(:all) do
+ @msg ='This operand need these options:'
+ @int = '1'
+ subject.stub(:create_integer => 1)
+ end
+
+ context 'integer' do
+ before { set_options(:min => nil, :max => nil, :minus => nil) }
+ it { subject.__send__(:integer).should == @int }
+ end
+
+ context 'decimal' do
+ before do
+ set_options(
+ :min => nil,
+ :max => nil,
+ :minus => nil,
+ :digits => 2
+ )
+ end
+ it { subject.__send__(:decimal).should match(/(?:#{@int}|0)\.\d\d?/) }
+ end
+
+ context 'fraction' do
+ before do
+ set_options(
+ :numerator_min => nil,
+ :numerator_max => nil,
+ :denominator_min => nil,
+ :denominator_max => nil,
+ :minus => nil
+ )
+ subject.should_receive(:numerator_part).and_return('a')
+ subject.should_receive(:denominator_part).and_return('b')
+ end
+ it { subject.__send__(:fraction).should == "a/b" }
+ end
+ end
+end
+
module ProblemExamples
def self.get(*types)
types.inject([]) {|memo, type|
- memo += __send__(type)
- }
+ memo += __send__(type) }
end
private
['(2a + 1)(3a - 2)', '(2 * a + 1) * (3 * a - 2)'],
['(x + 2)^2', '(x + 2)^2'],
['(3P - 2Q)^3', '(3 * P - 2 * Q)^3'],
- ['1 / (x + 1)(x + 2)', '1 / (x + 1) * (x + 2)'],
+ ['1 / (x + 1)(x + 2)', '1 / ((x + 1) * (x + 2))'],
['2x^3 + x - 1', '2 * x^3 + x - 1'],
- ['(X^2 + 2aX + a2)', '(X^2 + 2 * a * X + a * 2)'],
['(X^2 - Y^2)', '(X^2 - Y^2)'],
['root(2)root(8)', 'sqrt(2) * sqrt(8)'],
['sqrt(2)sqrt(8)', 'sqrt(2) * sqrt(8)'],
['3 * 3', '3 * 3'],
['4 / 4', '4 / 4'],
['5 div 5', '5 div 5'],
+ ['-233/23', '-233 / 23'],
+ ['(x^2 + 4)(y^3 - 2)', '(x^2 + 4) * (y^3 - 2)'],
+ ['(x^3 + 2)(x^2- 3)', '(x^3 + 2) * (x^2 - 3)'],
['2(x^2 + xy + y^2)', '2 * (x^2 + x * y + y^2)'],
['sqrt(2(x^(2 + 3) + xyz^5 + y^2))', 'sqrt(2 * (x^(2 + 3) + x * y * z^5 + y^2))'],
['sqrt(2(x^(2 + 3) + root(xyz^5) + y^2))', 'sqrt(2 * (x^(2 + 3) + sqrt(x * y * z^5) + y^2))'],
['(-24x + 37)(71x - 33)', '(-24 * x + 37) * (71 * x - 33)'],
['x^((3y^2+5y)(y^2+2-x))', 'x^((3 * y^2 + 5 * y) * (y^2 + 2 - x))'],
['-x^(-(-3y^2+-5y)(y^-2+2-x))', '-x^(-(-3 * y^2 + -5 * y) * (y^-2 + 2 - x))'],
- # TODO: need more pattern
-
- # divide and fraction
+ ['(x^3 + 1)(x^2 + 2)(x + 1)', '(x^3 + 1) * (x^2 + 2) * (x + 1)'],
+ ['(x^3 + 1)(x^2 + 2)(x + 1)(y^2 - 11)', '(x^3 + 1) * (x^2 + 2) * (x + 1) * (y^2 - 11)'],
+ ['(x^3 + 1)(x^2 + 2)(x + 1)(y^2 - 11)(y^3 - 4)', '(x^3 + 1) * (x^2 + 2) * (x + 1) * (y^2 - 11) * (y^3 - 4)'],
+ ['a - 1', 'a - 1'],
+ ['6a^2 - a - 1', '6 * a^2 - a - 1'],
['5 div 4', '5 div 4'],
['5.0 div 4', '5.0 div 4'],
['5/4', '5 / 4'],
['5.0/4', '5.0 / 4'],
+ ['.04324134213', '0.043'],
+ ['- .04324134213', '-0.043'],
+ ['-50/12 div 12*32', '-50 / 12 div (12 * 32)'],
+ ['-sqrt(2)', '-sqrt(2)'],
+ ['-(5 - 2x)', '(2x - 5)'],
+ # TODO: need more pattern
+ ]
+ end
+
+ def self.bad_patterns
+ [
+ '1 + ', ' * 2', ' * ', '4 / 4 5',
+ '2(x^2 + xy + y^2',
+ 'sqrt(2(x^2 + 3) + xyz^5 + y^2))',
+ 'sqrt(2(x^(2 + ) + rot(xyz^5) + y^2))',
+ '5xc*1/5 + 1 (34 - 1 /8 + 1)* / 1',
+ # TODO: need more pattern
]
end
end