OSDN Git Service

refacotred spec for arithmetic_base generator
[mint/mint-lib.git] / spec / spec_helper.rb
index cde9ef4..5716174 100644 (file)
 $:.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
@@ -25,9 +205,8 @@ module ProblemExamples
       ['(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)'],
@@ -47,6 +226,9 @@ module ProblemExamples
       ['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))'],
@@ -59,13 +241,32 @@ module ProblemExamples
       ['(-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