OSDN Git Service

add: social button
[pettanr/pettanr.git] / spec / models / picture_spec.rb
index bb5bf3d..5ce8081 100644 (file)
@@ -4,36 +4,48 @@ require 'spec_helper'
 
 describe Picture do
   before do
-    Factory :admin
-    @user = Factory( :user_yas)
-    @author = @user.author
-    @artist = Factory :artist_yas, :author_id => @author.id
-    @other_user = Factory( :user_yas)
-    @other_author = @other_user.author
-    @other_artist = Factory :artist_yas, :author_id => @other_author.id
-    @sp = Factory :system_picture
-    @lg = Factory :license_group
-    @license = Factory :license, :license_group_id => @lg.id, :system_picture_id => @sp.id
-    @op = Factory :original_picture, :artist_id => @artist.id
+    @admin = FactoryGirl.create :admin
+    @user = FactoryGirl.create( :user_yas)
+    @author = FactoryGirl.create :author, :user_id => @user.id
+    @artist = FactoryGirl.create :artist_yas, :author_id => @author.id
+    @other_user = FactoryGirl.create( :user_yas)
+    @other_author = FactoryGirl.create :author, :user_id => @other_user.id
+    @other_artist = FactoryGirl.create :artist_yas, :author_id => @other_author.id
+    @sp = FactoryGirl.create :system_picture
+    @lg = FactoryGirl.create :license_group
+    @license = FactoryGirl.create :license, :license_group_id => @lg.id, :system_picture_id => @sp.id
+    @op = FactoryGirl.create :original_picture, :artist_id => @artist.id
   end
   
   describe '検証に於いて' do
     before do
+      @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id
     end
     
-    it 'オーソドックスなデータなら通る' do
-      @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
-      @p.should be_valid
-    end
-    
-    context 'original_picture_idを検証するとき' do
-      before do
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
+    context 'オーソドックスなデータのとき' do
+      it '下限データが通る' do
+        @p.revision = 1
+        @p.ext = 'png' #リストにない拡張子は通らないし
+        @p.width = 1
+        @p.height = 1
+        @p.filesize = 1
+        @p.md5 = 'a'*32
+        @p.classname = 'a'*1
+        @p.should be_valid
       end
-      it 'テストデータの確認' do
-        @p.original_picture_id = @op.id
+      it '上限データが通る' do
+        @p.revision = 99999
+        @p.ext = 'jpeg'
+        @p.width = 99999
+        @p.height = 99999
+        @p.filesize = 2000000
+        @p.md5 = 'a'*32
+        @p.classname = 'a'*50
         @p.should be_valid
       end
+    end
+    
+    context 'original_picture_idを検証するとき' do
       it 'nullなら失敗する' do
         @p.original_picture_id = nil
         @p.should_not be_valid
@@ -48,13 +60,6 @@ describe Picture do
       end
     end
     context 'revisionを検証するとき' do
-      before do
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
-      end
-      it 'テストデータの確認' do
-        @p.revision = 1
-        @p.should be_valid
-      end
       it 'nullなら失敗する' do
         @p.revision = nil
         @p.should_not be_valid
@@ -65,13 +70,6 @@ describe Picture do
       end
     end
     context 'extを検証するとき' do
-      before do
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
-      end
-      it 'テストデータの確認' do
-        @p.ext = 'jpeg'
-        @p.should be_valid
-      end
       it 'nullなら失敗する' do
         @p.ext = ''
         @p.should_not be_valid
@@ -86,13 +84,6 @@ describe Picture do
       end
     end
     context 'widthを検証するとき' do
-      before do
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
-      end
-      it 'テストデータの確認' do
-        @p.width = 1
-        @p.should be_valid
-      end
       it 'nullなら失敗する' do
         @p.width = nil
         @p.should_not be_valid
@@ -111,13 +102,6 @@ describe Picture do
       end
     end
     context 'heightを検証するとき' do
-      before do
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
-      end
-      it 'テストデータの確認' do
-        @p.height = 1
-        @p.should be_valid
-      end
       it 'nullなら失敗する' do
         @p.height = nil
         @p.should_not be_valid
@@ -136,13 +120,6 @@ describe Picture do
       end
     end
     context 'filesizeを検証するとき' do
-      before do
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
-      end
-      it 'テストデータの確認' do
-        @p.filesize = 1
-        @p.should be_valid
-      end
       it 'nullなら失敗する' do
         @p.filesize = nil
         @p.should_not be_valid
@@ -160,14 +137,21 @@ describe Picture do
         @p.should_not be_valid
       end
     end
-    context 'artist_idを検証するとき' do
-      before do
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
+    context 'md5を検証するとき' do
+      it 'nullなら失敗する' do
+        @p.md5 = ''
+        @p.should_not be_valid
       end
-      it 'テストデータの確認' do
-        @p.artist_id = @artist.id
-        @p.should be_valid
+      it '31文字なら失敗する' do
+        @p.md5 = 'a'*31
+        @p.should_not be_valid
+      end
+      it '32文字以上なら失敗する' do
+        @p.md5 = 'a'*33
+        @p.should_not be_valid
       end
+    end
+    context 'artist_idを検証するとき' do
       it 'nullなら失敗する' do
         @p.artist_id = nil
         @p.should_not be_valid
@@ -182,13 +166,6 @@ describe Picture do
       end
     end
     context 'license_idを検証するとき' do
-      before do
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
-      end
-      it 'テストデータの確認' do
-        @p.license_id = @license.id
-        @p.should be_valid
-      end
       it 'nullなら失敗する' do
         @p.license_id = nil
         @p.should_not be_valid
@@ -197,49 +174,256 @@ describe Picture do
         @p.license_id = 'a'
         @p.should_not be_valid
       end
-      it 'å­\98å\9c¨ã\81\99ã\82\8bã\83©ã\82¤ã\82»ã\83³ã\82¹ã\82°ã\83«ã\83¼ã\83\97ã\81§ã\81ªã\81\91ã\82\8cã\81°å¤±æ\95\97ã\81\99ã\82\8b' do
+      it '存在するライセンスでなければ失敗する' do
         @p.license_id = 0
         @p.should_not be_valid
       end
     end
     context 'artist_nameを検証するとき' do
-      before do
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
-      end
-      it 'テストデータの確認' do
-        @p.artist_name = 'a'
-        @p.should be_valid
-      end
       it 'nullなら失敗する' do
         @p.artist_name = nil
         @p.should_not be_valid
       end
     end
+    context 'classnameを検証するとき' do
+      it 'nullなら失敗する' do
+        @p.classname = ''
+        @p.should_not be_valid
+      end
+      it '51文字以上なら失敗する' do
+        @p.classname = 'a'*51
+        @p.should_not be_valid
+      end
+    end
     context 'creditを検証するとき' do
-      before do
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
+    end
+    context 'settingsを検証するとき' do
+    end
+  end
+  
+  describe '文字コード検証に於いて' do
+    before do
+      @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id
+    end
+    
+    context 'artist_nameを検証するとき' do
+      it 'Shift JISなら失敗する' do
+        @p.artist_name = "\x83G\x83r\x83]\x83D"
+        lambda{
+          @p.valid_encode
+        }.should raise_error(Pettanr::BadRequest)
       end
-      it 'テストデータの確認' do
-        @p.credit = 'a'
-        @p.should be_valid
+    end
+    
+    context 'classnameを検証するとき' do
+      it 'Shift JISなら失敗する' do
+        @p.classname = "\x83G\x83r\x83]\x83D"
+        lambda{
+          @p.valid_encode
+        }.should raise_error(Pettanr::BadRequest)
       end
     end
+    
+    context 'creditを検証するとき' do
+      it 'Shift JISなら失敗する' do
+        @p.credit = "\x83G\x83r\x83]\x83D"
+        lambda{
+          @p.valid_encode
+        }.should raise_error(Pettanr::BadRequest)
+      end
+    end
+    
     context 'settingsを検証するとき' do
+      it 'Shift JISなら失敗する' do
+        @p.settings = "\x83G\x83r\x83]\x83D"
+        lambda{
+          @p.valid_encode
+        }.should raise_error(Pettanr::BadRequest)
+      end
+    end
+    
+  end
+  
+  describe 'デフォルト値補充に於いて' do
+    it 'defined' do
+      @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id
+      @p.supply_default
+    end
+  end
+  
+  describe '上書き補充に於いて' do
+    before do
+      attr = {:ext => 'jpeg', :width => 264, :height => 265, :filesize => 266, 
+        :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, 
+        :artist_name => 'tester', :classname => 'Tester', :credit => {:title => 'cap'}.to_json.to_s, :settings => {:set => 1}.to_json.to_s}
+      @rp = FactoryGirl.build :resource_picture, attr
+      @p = FactoryGirl.build :picture, :original_picture_id => nil, :license_id => nil, :artist_id => nil, :revision => nil
+    end
+    it 'width, height, ext, filesize, md5, original_picture_idが設定されている' do
+      @p.overwrite @rp
+      @p.width.should eq 264
+      @p.height.should eq 265
+      @p.ext.should eq 'jpeg'
+      @p.filesize.should eq 266
+      @p.md5.should eq @rp.md5
+      @p.original_picture_id.should eq @op.id
+    end
+    it 'license_id, artist_id, artist_name, classname, credit, settingsが設定されている' do
+      @p.overwrite @rp
+      @p.license_id.should eq @license.id
+      @p.artist_id.should eq @artist.id
+      @p.artist_name.should eq 'tester'
+      @p.classname.should eq 'Tester'
+      @p.credit.should match /title/
+      @p.settings.should match /set/
+    end
+    it 'new_revisionに問い合わせている' do
+      Picture.any_instance.stub(:new_revision).with(any_args).and_return(3)
+      Picture.any_instance.should_receive(:new_revision).with(any_args).exactly(1)
+      @p.overwrite @rp
+    end
+    it 'revisionは、new_revisionに設定されている' do
+      Picture.any_instance.stub(:new_revision).with(any_args).and_return(3)
+      @p.overwrite @rp
+      @p.revision.should eq 3
+    end
+  end
+  
+  describe '所持判定に於いて' do
+    before do
+      @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id
+    end
+    context '事前チェックする' do
+      it '自身にロールリストからの絵師取得を依頼している' do
+        Picture.should_receive(:get_artist_from_roles).with(any_args).exactly(1)
+        r = @p.own?([@artist])
+      end
+    end
+    context 'ロール内絵師が取得できるとき' do
       before do
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
       end
-      it 'テストデータの確認' do
-        @p.settings = 'a'
-        @p.should be_valid
+      it 'ロール内絵師のidが自身の絵師idと一致するなら許可する' do
+        Picture.stub(:get_artist_from_roles).with(any_args).and_return(@artist)
+        r = @p.own?([@artist])
+        r.should be_true
+      end
+      it 'ロール内絵師のidが自身の絵師idと一致しないならno' do
+        Picture.stub(:get_artist_from_roles).with(any_args).and_return(@other_artist)
+        @p.own?(@other_artist).should be_false
+      end
+    end
+    context 'ロール内絵師が取得できないとき' do
+      before do
+        Picture.stub(:get_artist_from_roles).with(any_args).and_return(nil)
+      end
+      it 'Falseを返す' do
+        r = @p.own?([@artist])
+        r.should be_false
       end
     end
   end
-  describe '補充に於いて' do
+  
+  describe '閲覧許可に於いて' do
+    before do
+      @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id
+    end
+    it 'Trueを返す。' do
+      r = @p.visible?(@artist)
+      r.should be_true
+    end
   end
+  
+  describe '詳細閲覧許可に於いて' do
+    before do
+      @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id
+    end
+    context '自身に原画がリンクしていないとき' do
+      before do
+        Picture.any_instance.stub(:original_picture).with(any_args).and_return(nil)
+      end
+      it 'Falseを返す' do
+        r = @p.showable?(@author)
+        r.should be_false
+      end
+    end
+    it '自作の実素材ならyes' do
+      Picture.any_instance.stub(:own?).with(any_args).and_return(true)
+      @p.showable?(@artist).should == true
+    end
+    context '他人の実素材のとき' do
+      before do
+        Picture.any_instance.stub(:own?).with(any_args).and_return(false)
+      end
+      it '自身にhead判定と有効性判定を問い合わせ、両者がTrueならTrueを返す。' do
+        Picture.any_instance.stub(:head?).with(any_args).and_return(true)
+        Picture.any_instance.stub(:enable?).with(any_args).and_return(true)
+        r = @p.showable?(@author)
+        r.should be_true
+      end
+      it 'head判定がFalseならFalseを返す。' do
+        Picture.any_instance.stub(:head?).with(any_args).and_return(false)
+        Picture.any_instance.stub(:enable?).with(any_args).and_return(true)
+        r = @p.showable?(@author)
+        r.should be_false
+      end
+      it '有効性判定がFalseならFalseを返す。' do
+        Picture.any_instance.stub(:enable?).with(any_args).and_return(false)
+        Picture.any_instance.stub(:head?).with(any_args).and_return(true)
+        r = @p.showable?(@author)
+        r.should be_false
+      end
+    end
+  end
+  
+  describe 'ファイル名に於いて' do
+    before do
+      @p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id, :ext => 'png'
+    end
+    it 'id+拡張子のフォーマットで返す' do
+      r = @p.filename
+      r.should eq "#{@p.id}.png"
+    end
+  end
+  
+  describe 'gifファイル名に於いて' do
+    before do
+      @p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id, :ext => 'gif'
+    end
+    it 'id.gifのフォーマットで返す' do
+      r = @p.filename
+      r.should eq "#{@p.id}.gif"
+    end
+  end
+  
+  describe 'MimeTypeに於いて' do
+    before do
+      @p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id, :ext => 'png'
+    end
+    it 'image/拡張子のフォーマットで返す' do
+      r = @p.mime_type
+      r.should eq "image/png"
+    end
+  end
+  
+  describe 'ファイルのurlに於いて' do
+    before do
+      @p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id
+      Picture.any_instance.stub(:filename).and_return('3.gif')
+    end
+    it 'ファイル名取得を依頼している' do
+      Picture.any_instance.should_receive(:filename).exactly(1)
+      @p.url
+    end
+    it '/pictures/3.gifのフォーマットで返す' do
+      r = @p.url
+      r.should eq "/pictures/3.gif"
+    end
+  end
+  
   describe '最新Revision取得に於いて' do
     context '初めての原画を公開したとき' do
       before do
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
+        @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id
       end
       it 'Revisionは1となる' do
         @p.new_revision.should eq 1
@@ -247,8 +431,8 @@ describe Picture do
     end
     context 'HEADが1のとき' do
       before do
-        Factory :picture, :revision => 1, :original_picture_id => @op.id, :license_id => @license.id
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
+        FactoryGirl.create :picture, :revision => 1, :original_picture_id => @op.id, :license_id => @license.id
+        @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id
       end
       it 'Revisionは2となる' do
         @p.new_revision.should eq 2
@@ -256,50 +440,295 @@ describe Picture do
     end
     context 'HEADが5のとき' do
       before do
-        Factory :picture, :revision => 1, :original_picture_id => @op.id, :license_id => @license.id
-        Factory :picture, :revision => 5, :original_picture_id => @op.id, :license_id => @license.id
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
+        FactoryGirl.create :picture, :revision => 1, :original_picture_id => @op.id, :license_id => @license.id
+        FactoryGirl.create :picture, :revision => 5, :original_picture_id => @op.id, :license_id => @license.id
+        @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id
       end
       it 'Revisionは6となる' do
         @p.new_revision.should eq 6
       end
     end
   end
-  describe '素材からのコピーデータセットに於いて' do
-    before do\r
-      @op = Factory :original_picture, :artist_id => @artist.id
-      attr = {:ext => 'jpeg', :width => 264, :height => 265, :filesize => 266, 
-        :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, 
-        :artist_name => 'tester', :credit => {:title => 'cap'}.to_json.to_s, :settings => {:set => 1}.to_json.to_s}\r
-      @rp = Factory.build :resource_picture, attr
-      @p = Factory.build :picture
-    end
-    it '素材オブジェクトから属性を取り出して対象実素材にセットしている' do
-      res = @p.copy_data(@rp)\r
-      @p.ext.should eq 'jpeg'\r
-      @p.width.should eq 264\r
-      @p.height.should eq 265\r
-      @p.filesize.should eq 266\r
-      @p.artist_id.should eq @artist.id\r
-      @p.license_id.should eq @license.id\r
-      @p.original_picture_id.should eq @op.id\r
-      @p.artist_name.should eq 'tester'\r
-      @p.credit.should match /title/\r
-      @p.settings.should match /set/\r
-    end\r
+  
+  describe '有効性判定に於いて' do
+    before do
+      @p = FactoryGirl.create :picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id 
+      @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :picture_id => @p.id
+      Picture.any_instance.stub(:head).and_return(@p)
+    end
+    context '自身のheadとリンクした素材があるとき' do
+      before do
+        Picture.any_instance.stub(:resource_picture).and_return(@rp)
+      end
+      it 'trueを返す' do
+        res = @p.enable?
+        res.should be_true
+      end
+    end
+    context '自身のheadとリンクした素材がないとき' do
+      before do
+        Picture.any_instance.stub(:resource_picture).and_return(nil)
+      end
+      it 'falseを返す' do
+        res = @p.enable?
+        res.should be_false
+      end
+    end
+  end
+  
+  describe 'head取得に於いて' do
+    before do
+      #旧版
+      @op = FactoryGirl.create :original_picture, :artist_id => @artist.id
+      @p = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 0,
+        :original_picture_id => @op.id, :md5 => 'a' * 32
+      #最新版
+      @p2 = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 1,
+        :original_picture_id => @op.id, :md5 => 'b' * 32
+      #除外すべき無関係画像
+      @op2 = FactoryGirl.create :original_picture, :artist_id => @artist.id
+      @p3 = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 0,
+        :original_picture_id => @op2.id, :md5 => 'C' * 32
+    end
+    context 'つつがなく終わるとき' do
+      before do
+        #素材は有効
+        @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :picture_id => @p2.id
+      end
+      it '最新版を返す' do
+        res = @p.head
+        res.should eq @p2
+      end
+    end
+    context '無効な素材(素材とリンクしてない)とき' do
+      it '同じく最新版を返す' do
+        res = @p.head
+        res.should eq @p2
+      end
+    end
+  end
+  
+  describe 'head判定に於いて' do
+    before do
+      #旧版
+      @op = FactoryGirl.create :original_picture, :artist_id => @artist.id
+      @p = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 0,
+        :original_picture_id => @op.id, :md5 => 'a' * 32
+      #最新版
+      @p2 = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 1,
+        :original_picture_id => @op.id, :md5 => 'b' * 32
+      @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :picture_id => @p2.id
+    end
+    context '旧版のとき' do
+      it 'falseを返す' do
+        res = @p.head?
+        res.should be_false
+      end
+    end
+    context '最新版のとき' do
+      it 'trueを返す' do
+        res = @p2.head?
+        res.should be_true
+      end
+    end
+  end
+  
+  describe 'フォーマット変換対象判定に於いて' do
+    before do
+      @p = FactoryGirl.build :picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id
+    end
+    context '変換するケース' do
+      it '画像フォーマットがpngかつライセンスの変換禁止フラグが無効のときTrue' do
+        Picture.any_instance.stub(:flag_gif_convert).with(any_args).and_return(0)
+        @p.ext = 'png'
+        @p.to_gif?.should be_true
+      end
+    end
+    context '変換しないケース' do
+      it '画像フォーマットがpngでない' do
+        Picture.any_instance.stub(:flag_gif_convert).with(any_args).and_return(0)
+        @p.ext = 'gif'
+        @p.to_gif?.should be_false
+      end
+      it '変換禁止フラグが無効' do
+        Picture.any_instance.stub(:flag_gif_convert).with(any_args).and_return(-1)
+        @p.ext = 'png'
+        @p.to_gif?.should be_false
+      end
+    end
+  end
+  
+  describe 'サブディレクトリリストに於いて' do
+    before do
+      @p = FactoryGirl.build :picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id
+    end
+    it '配列で返す' do
+      Picture.any_instance.stub(:flag_gif_convert).with(any_args).and_return(0)
+      r = @p.subdirs
+      r.is_a?(Array).should be_true
+    end
+    it '本画像(ベースディレクトリ)を含んでいる' do
+      Picture.any_instance.stub(:flag_reverse).with(any_args).and_return(0)
+      r = @p.subdirs
+      r.include?('').should be_true
+    end
+    context '反転が許可されているとき' do
+      it '垂直・水平・垂直水平反転ディレクトリも返す' do
+        Picture.any_instance.stub(:flag_reverse).with(any_args).and_return(0)
+        r = @p.subdirs
+        r.include?('v').should be_true
+        r.include?('h').should be_true
+        r.include?('vh').should be_true
+      end
+    end
+    context '反転が許可されていないとき' do
+      it '本画像(ベースディレクトリ)だけを返す' do
+        Picture.any_instance.stub(:flag_reverse).with(any_args).and_return(-1)
+        r = @p.subdirs
+        r.size.should eq 1
+      end
+    end
+  end
+  
+  describe 'md5重複リストに於いて' do
+    before do
+      @op = FactoryGirl.create :original_picture, :artist_id => @artist.id
+      @p = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 0,
+        :original_picture_id => @op.id, :md5 => 'a' * 32
+      @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :picture_id => @p.id
+      @op2 = FactoryGirl.create :original_picture, :artist_id => @artist.id
+      @p2 = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 0,
+        :original_picture_id => @op2.id, :md5 => 'b' * 32
+      @op3 = FactoryGirl.create :original_picture, :artist_id => @artist.id
+    end
+    context '除外する原画idで指定されていないとき' do
+      it 'リストを返す' do
+        res = Picture.list_by_md5(@p.md5)
+        res.is_a?(Array).should be_true
+      end
+      it 'md5が違えば含まない' do
+        res = Picture.list_by_md5(@p.md5)
+        res.include?(@p2).should be_false
+      end
+      it '更新日時順' do
+        @p3 = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 1,
+          :original_picture_id => @op2.id, :md5 => 'C' * 32
+        @p4 = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 1,
+          :original_picture_id => @op3.id, :md5 => @p3.md5, :updated_at => Time.now + 100
+        res = Picture.find_by_md5(@p3.md5)
+        res.should eq [@p4, @p3]
+      end
+    end
+    context '除外する原画idで指定されたとき' do
+      it 'リストを返す' do
+        res = Picture.list_by_md5(@p.md5, @p.original_picture_id)
+        res.is_a?(Array).should be_true
+      end
+      it 'md5が違えば含まない' do
+        res = Picture.list_by_md5(@p.md5, @p.original_picture_id)
+        res.include?(@p2).should be_false
+      end
+      it '同一原画は含まない' do
+        res = Picture.list_by_md5(@p.md5, @p.original_picture_id)
+        res.empty?.should be_true
+      end
+      it '同一原画は旧版でも含まない' do
+        @p3 = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 1,
+          :original_picture_id => @op.id, :md5 => 'a' * 32
+        res = Picture.list_by_md5(@p.md5, @p.original_picture_id)
+        res.empty?.should be_true
+      end
+      it '他所の原画なら含む' do
+        @p3 = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 1,
+          :original_picture_id => @op2.id, :md5 => 'a' * 32
+        res = Picture.list_by_md5(@p.md5, @p.original_picture_id)
+        res.should eq [@p3]
+      end
+      it '他所の原画でもmd5が違えば含まない' do
+        @p3 = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 1,
+          :original_picture_id => @op2.id, :md5 => 'c' * 32
+        res = Picture.list_by_md5(@p.md5, @p.original_picture_id)
+        res.empty?.should be_true
+      end
+      it '更新日時順' do
+        @p3 = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 1,
+          :original_picture_id => @op2.id, :md5 => 'a' * 32
+        @p4 = FactoryGirl.create :picture, :artist_id => @artist.id, :license_id => @license.id, :revision => 1,
+          :original_picture_id => @op3.id, :md5 => 'a' * 32, :updated_at => Time.now + 100
+        res = Picture.list_by_md5(@p.md5, @p.original_picture_id)
+        res.should eq [@p4, @p3]
+      end
+    end
+  end
+  
+  describe 'md5重複判定に於いて' do
+    before do
+      @op = FactoryGirl.create :original_picture, :artist_id => @artist.id
+      @op2 = FactoryGirl.create :original_picture, :artist_id => @artist.id
+      @p = FactoryGirl.create :picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :revision => 0
+      @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :picture_id => @p.id
+    end
+    context '同一原画以外に同じ値があるとき' do
+      before do
+        @p2 = FactoryGirl.create :picture, :artist_id => @artist.id, :original_picture_id => @op2.id, :license_id => @license.id
+      end
+      it 'trueを返す' do
+        res = Picture.exist_by_md5(@p.md5, @p.original_picture_id)
+        res.should be_true
+      end
+    end
+    context '同一原画以外に同じ値がないとき' do
+      it 'falseを返す' do
+        res = Picture.exist_by_md5(@p.md5, @p.original_picture_id)
+        res.should be_false
+      end
+    end
+    context '同一原画に同じ値があるとき' do
+      before do
+        @p2 = FactoryGirl.create :picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :revision => 1
+      end
+      it 'falseを返す' do
+        res = Picture.exist_by_md5(@p.md5, @p.original_picture_id)
+        res.should be_false
+      end
+    end
+  end
+  
+  describe '単体取得に於いて' do
+    before do
+      @p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id
+    end
+    context 'つつがなく終わるとき' do
+      it '閲覧許可を問い合わせている' do
+        Picture.any_instance.stub(:visible?).with(any_args).and_return(true)
+        Picture.any_instance.should_receive(:visible?).with(any_args).exactly(1)
+        r = Picture.show @p.id, @author
+      end
+    end
+    it '指定の実素材を返す' do
+      r = Picture.show @p.id, @author
+      r.should eq @p
+    end
+    context '他人の実素材を開こうとしたとき' do
+      it '403Forbidden例外を返す' do
+        Picture.any_instance.stub(:visible?).and_return(false)
+        lambda{
+          r = Picture.show @p.id, @other_author
+        }.should raise_error(ActiveRecord::Forbidden)
+      end
+    end
+    context '存在しない実素材を開こうとしたとき' do
+      it '404RecordNotFound例外を返す' do
+        lambda{
+          r = Picture.show 0, @author
+        }.should raise_error(ActiveRecord::RecordNotFound)
+      end
+    end
   end
   
   describe '作成に於いて' do
     before do
-      #RMagickのスタブをおいておく
-      class Mgk ; class Image ; end ; end
-      @filesize = 76543
-      Mgk::Image.stub(:from_blob).with(any_args).and_return([Mgk.new])
-      Mgk.any_instance.stub(:format).with(any_args).and_return('png')
-      Mgk.any_instance.stub(:rows).with(any_args).and_return(200)
-      Mgk.any_instance.stub(:columns).with(any_args).and_return(100)
-      Mgk.any_instance.stub(:filesize).with(any_args).and_return(@filesize)
-      Mgk.any_instance.stub(:to_blob).with(any_args).and_return('data')
+      @imager = ImagerTest.load "abc\ndef\nghi"
       #原画ファイル削除だけは必ず成功するものとしておく
       PictureIO::LocalPicture.any_instance.stub(:delete).with(any_args).and_return(true)
     end
@@ -307,274 +736,244 @@ describe Picture do
       before do
         #すべての処理が正常パターンで通過すれば、一番深い分岐まで通る。
         #それで外部のメソッド呼び出しだけに着目してテストする。
-        Picture.any_instance.stub(:save).with(any_args).and_return(true)\r
-        Picture.any_instance.stub(:store_picture).with(any_args).and_return(true)\r
-        Picture.any_instance.stub(:to_gif?).with(any_args).and_return(true)\r
-        class GifMgk < Mgk ; end  #store_pictureは二回呼び出される。区別をつけるために\r
-        @gifmgk = GifMgk.new      #パラメータを二種類用意する。\r
-        Picture.stub(:png_to_gif).with(any_args).and_return(@gifmgk)
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
-      end
-      it '最新Revisionを取得している' do
-        Picture.any_instance.should_receive(:new_revision).with(any_args).exactly(1)
-        res = @p.store(Mgk.new)\r
-      end\r
+        Picture.any_instance.stub(:save).with(any_args).and_return(true)
+        Picture.any_instance.stub(:store_picture).with(any_args).and_return(true)
+        Picture.any_instance.stub(:to_gif?).with(any_args).and_return(true)
+        @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id, :ext => 'png'
+      end
       it '自身を保存している' do
         Picture.any_instance.should_receive(:save).with(any_args).exactly(1)
-        res = @p.store(Mgk.new)\r
-      end\r
-      it '画像ファイルの作成機能で画像を保存している' do\r
-        mgk = Mgk.new   #一回目の本画像保存は与えたオブジェクトを使って保存する。
-        Picture.any_instance.should_receive(:store_picture).with(mgk).exactly(1)
-        res = @p.store(mgk)\r
-      end\r
+        r = @p.store(@imager)
+      end
+      it '画像ファイルの作成機能で画像を保存している' do
+        Picture.any_instance.stub(:filename).with(any_args).and_return('1.png')
+        #二回目の保存はgif変換の結果を渡す。
+        Picture.any_instance.should_receive(:store_picture).with(any_args).exactly(2)
+        r = @p.store(@imager)
+      end
       it '自身にgifフォーマット変換対象かを問い合わせている' do
         Picture.any_instance.should_receive(:to_gif?).with(any_args).exactly(1)
-        res = @p.store(Mgk.new)\r
-      end\r
-      it '自身にGifフォーマット変換を依頼している' do
-        Picture.should_receive(:png_to_gif).with(any_args).exactly(1)
-        res = @p.store(Mgk.new)\r
-      end\r
-      it '画像ファイルの作成機能でgif画像を保存している' do\r
-        #二回目の保存はgif変換の結果を渡す。
-        Picture.any_instance.should_receive(:store_picture).with(@gifmgk).exactly(1)
-        res = @p.store(Mgk.new)\r
-      end\r
+        r = @p.store(@imager)
+      end
     end
     context 'つつがなく終わるとき' do
       before do
         #すべての処理を正常パターンで通過させ、保存機能をチェックする。
-#        Picture.any_instance.stub(:save).with(any_args).and_return(true)\r
-        Picture.any_instance.stub(:store_picture).with(any_args).and_return(true)\r
-        Picture.any_instance.stub(:to_gif?).with(any_args).and_return(true)\r
-        class GifMgk < Mgk ; end  #store_pictureは二回呼び出される。区別をつけるために\r
-        @gifmgk = GifMgk.new      #パラメータを二種類用意する。\r
-        Picture.stub(:png_to_gif).with(any_args).and_return(@gifmgk)
-        @p = Factory.build :picture, :revision => nil, :original_picture_id => @op.id, :license_id => @license.id
+        Picture.any_instance.stub(:store_picture).with(any_args).and_return(true)
+        Picture.any_instance.stub(:to_gif?).with(any_args).and_return(true)
+        @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id, :ext => 'png'
       end
       it 'Trueを返す' do
-        res = @p.store(Mgk.new)\r
-        res.should be_true\r
-      end\r
-      it 'Revisionに最新Revisionセット' do
-        res = @p.store(Mgk.new)\r
-        @p.revision.should eq 1\r
-      end\r
-      it '自身が保存されている' do\r
+        r = @p.store(@imager)
+        r.should be_true
+      end
+      it '自身が保存されている' do
         lambda {
-          res = @p.store(Mgk.new)\r
-        }.should change Picture, :count\r
-      end\r
+          r = @p.store(@imager)
+        }.should change Picture, :count
+      end
     end
     context 'gif変換なしで、つつがなく終わるとき' do
       before do
         #すべての処理を正常パターンで通過させ、保存機能をチェックする。
-        Picture.any_instance.stub(:save).with(any_args).and_return(true)\r
-        Picture.any_instance.stub(:store_picture).with(any_args).and_return(true)\r
-        Picture.any_instance.stub(:to_gif?).with(any_args).and_return(false)\r
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
+        Picture.any_instance.stub(:store_picture).with(any_args).and_return(true)
+        Picture.any_instance.stub(:to_gif?).with(any_args).and_return(false)
+        @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id, :ext => 'png'
       end
       it 'Trueを返す' do
-        res = @p.store(Mgk.new)\r
-        res.should be_true\r
-      end\r
+        r = @p.store(@imager)
+        r.should be_true
+      end
       it 'gif保存は呼ばれていない' do
-        #二回目の画像作成が呼び出されないで1回こっきりならgif保存は呼ばれていないんだろう。\r
+        #二回目の画像作成が呼び出されないで1回こっきりならgif保存は呼ばれていないんだろう。
         Picture.any_instance.should_receive(:store_picture).with(any_args).exactly(1)
-        res = @p.store(Mgk.new)\r
-      end\r
+        r = @p.store(@imager)
+      end
     end
     #以下から例外ケース。処理先頭から失敗させていく
     context '自身の保存に失敗したとき' do
       before do
-        Picture.any_instance.stub(:save).with(any_args).and_return(false)\r
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
+        Picture.any_instance.stub(:save).with(any_args).and_return(false)
+        @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id, :ext => 'png'
       end
       it 'Falseを返す' do
-        res = @p.store(Mgk.new)\r
-        res.should be_false\r
-      end\r
+        r = @p.store(@imager)
+        r.should be_false
+      end
       it '更新されていない' do
-        @p.store(Mgk.new)
-        @p.should be_a_new Picture\r
+        r = @p.store(@imager)
+        @p.should be_a_new Picture
       end
     end
     context '画像の保存に失敗したとき' do
       before do
-        Picture.any_instance.stub(:save).with(any_args).and_return(true)\r
-        Picture.any_instance.stub(:store_picture).with(any_args).and_return(false)\r
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
+        Picture.any_instance.stub(:store_picture).with(any_args).and_return(false)
+        @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id, :ext => 'png'
       end
       it 'Falseを返す' do
-        res = @p.store(Mgk.new)\r
-        res.should be_false\r
-      end\r
-      it 'gif変換判定は呼ばれていない' do\r
-        Picture.any_instance.should_not_receive(:to_gif?).with(any_args)
-        res = @p.store(Mgk.new)\r
-      end\r
+        r = @p.store(@imager)
+        r.should be_false
+      end
+      it 'gif変換判定は呼ばれていない' do
+        Picture.any_instance.should_not_receive(:to_gif?).with(any_args).exactly(0)
+        r = @p.store(@imager)
+      end
     end
     context 'gif変換に失敗したとき' do
       before do
-        Picture.any_instance.stub(:save).with(any_args).and_return(true)\r
-        Picture.any_instance.stub(:store_picture).with(any_args).and_return(true)\r
-        Picture.any_instance.stub(:to_gif?).with(any_args).and_return(true)\r
-        Picture.stub(:png_to_gif).with(any_args).and_return(false)
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
+        Picture.any_instance.stub(:store_picture).with(any_args).and_return(true)
+        Picture.any_instance.stub(:to_gif?).with(any_args).and_return(true)
+        ImagerTest.stub(:load).with(any_args).and_return(false)
+        @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id, :ext => 'png'
       end
       it 'Falseを返す' do
-        res = @p.store(Mgk.new)\r
-        res.should be_false\r
-      end\r
-      it 'gif画像の保存は呼ばれていない' do\r
-        #本画像の保存があるので、一度は呼ばれる\r
+        r = @p.store(@imager)
+        r.should be_false
+      end
+      it 'gif画像の保存は呼ばれていない' do
+        #本画像の保存があるので、一度は呼ばれる
         Picture.any_instance.should_receive(:store_picture).with(any_args).exactly(1)
-        res = @p.store(Mgk.new)\r
-      end\r
+        r = @p.store(@imager)
+      end
     end
     context 'gif画像の保存に失敗したとき' do
-      before do\r
-        @mgk = Mgk.new
-        Picture.any_instance.stub(:save).with(any_args).and_return(true)\r
-        Picture.any_instance.stub(:store_picture).with(@mgk).and_return(true)\r
-        Picture.any_instance.stub(:to_gif?).with(any_args).and_return(true)\r
-        class GifMgk < Mgk ; end  #store_pictureは二回呼び出される。区別をつけるために\r
-        @gifmgk = GifMgk.new      #パラメータを二種類用意する。\r
-        Picture.stub(:png_to_gif).with(any_args).and_return(@gifmgk)
-        Picture.any_instance.stub(:store_picture).with(@gifmgk).and_return(false)\r
-        @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
+      before do
+        @gifimager = @imager.to_gif
+        ImagerTest.any_instance.stub(:to_gif).with(any_args).and_return(@gifimager)
+        Picture.any_instance.stub(:filename).with(any_args).and_return('1.png')
+        Picture.any_instance.stub(:gifname).with(any_args).and_return('1.gif')
+        Picture.any_instance.stub(:store_picture).with(@imager, '1.png').and_return(true)
+        Picture.any_instance.stub(:to_gif?).with(any_args).and_return(true)
+        Picture.any_instance.stub(:store_picture).with(@gifimager, '1.gif').and_return(false)
+        @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id, :ext => 'png'
       end
       it 'Falseを返す' do
-        res = @p.store(@mgk)\r
-        res.should be_false\r
-      end\r
-    end
-  end\r
-  
-  describe '反転画像の保存先に於いて' do\r
-    before do
-      @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
+        r = @p.store(@imager)
+        r.should be_false
+      end
     end
-    context '禁止のとき' do
-      it 'ベースディレクトリだけを返す' do
-        Picture.any_instance.should_receive(:flag_reverse).with(any_args).and_return(-1)
-        r = @p.subdirs
-        r.should have(1).item \r
-      end\r
-      it 'ベースディレクトリだけを返す' do
-        Picture.any_instance.should_receive(:flag_reverse).with(any_args).and_return(-1)
-        r = @p.subdirs
-        r.first.should eq ''\r
-      end\r
-    end\r
-    context '許可のとき' do
-      it 'ベースディレクトリと反転3種を返す' do
-        Picture.any_instance.should_receive(:flag_reverse).with(any_args).and_return(1)
-        r = @p.subdirs
-        r.should have(4).item \r
-      end\r
-      it 'ベースディレクトリと反転3種を返す' do
-        Picture.any_instance.should_receive(:flag_reverse).with(any_args).and_return(1)
-        r = @p.subdirs
-        r.last.should eq 'vh'\r
-      end\r
-    end\r
-  end\r
+  end
   
-  describe '画像ファイルの作成に於いて' do\r
-    #PictureIo経由で画像を保存するための機能。ファイル名に自身のidを使うので事前に自身の保存が必要。\r
+  describe '画像ファイルの作成に於いて' do
+    #PictureIo経由で画像を保存するための機能。ファイル名に自身のidを使うので事前に自身の保存が必要。
     before do
-      #RMagickのスタブをおいておく
-      class Mgk ; class Image ; end ; end
-      @filesize = 76543
-      Mgk::Image.stub(:from_blob).with(any_args).and_return([Mgk.new])
-      Mgk.any_instance.stub(:format).with(any_args).and_return('png')
-      Mgk.any_instance.stub(:rows).with(any_args).and_return(200)
-      Mgk.any_instance.stub(:columns).with(any_args).and_return(100)
-      Mgk.any_instance.stub(:filesize).with(any_args).and_return(@filesize)
-      Mgk.any_instance.stub(:to_blob).with(any_args).and_return('data')
+      @imager = ImagerTest.load "abc\ndef\nghi"
       #原画ファイル削除だけは必ず成功するものとしておく
       PictureIO::LocalPicture.any_instance.stub(:delete).with(any_args).and_return(true)
       
-      Picture.any_instance.stub(:subdirs).with(any_args).and_return(['', 'v', 'h', 'vh'])\r
-      Picture.any_instance.stub(:h).with(any_args).and_return('data')
-      Picture.any_instance.stub(:v).with(any_args).and_return('data')
-      Picture.any_instance.stub(:vh).with(any_args).and_return('data')
-      @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id
+      Picture.any_instance.stub(:subdirs).with(any_args).and_return(['', 'v', 'h', 'vh'])
+      @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id, :ext => 'png'
     end
     context '事前チェック' do
       before do
         #すべての処理を正常パターンで通過させ、保存機能をチェックする。
         PictureIO.picture_io.stub(:put).with(any_args).and_return(true)
       end
-      it '画像ファイルの保存が4回呼ばれる' do\r
+      it '画像ファイルの保存が4回呼ばれる' do
         PictureIO.picture_io.should_receive(:put).with(any_args).exactly(4)
-        res = @p.store_picture(Mgk.new)\r
-      end\r
-      it '画像ファイルのベースへの保存が1回呼ばれる' do\r
-        PictureIO.picture_io.should_receive(:put).with('data', @p.filename, '').exactly(1)
-        res = @p.store_picture(Mgk.new)\r
-      end\r
-      it '画像ファイルの垂直反転への保存が1回呼ばれる' do\r
-        PictureIO.picture_io.should_receive(:put).with('data', @p.filename, 'v').exactly(1)
-        res = @p.store_picture(Mgk.new)\r
-      end\r
-      it '画像ファイルの水平反転への保存が1回呼ばれる' do\r
-        PictureIO.picture_io.should_receive(:put).with('data', @p.filename, 'h').exactly(1)
-        res = @p.store_picture(Mgk.new)\r
-      end\r
-      it '画像ファイルの垂直水平反転への保存が1回呼ばれる' do\r
-        PictureIO.picture_io.should_receive(:put).with('data', @p.filename, 'vh').exactly(1)
-        res = @p.store_picture(Mgk.new)\r
-      end\r
-      it '垂直反転が1回呼ばれる' do\r
-        Picture.any_instance.should_receive(:v).with(any_args).exactly(1)
-        res = @p.store_picture(Mgk.new)\r
-      end\r
-      it '水平反転が1回呼ばれる' do\r
-        Picture.any_instance.should_receive(:h).with(any_args).exactly(1)
-        res = @p.store_picture(Mgk.new)\r
-      end\r
-      it '垂直水平反転が1回呼ばれる' do\r
-        Picture.any_instance.should_receive(:vh).with(any_args).exactly(1)
-        res = @p.store_picture(Mgk.new)\r
-      end\r
+        r = @p.store_picture(@imager, '1.png')
+      end
+      it '画像ファイルのベースへの保存が1回呼ばれる' do
+        PictureIO.picture_io.should_receive(:put).with("abc\ndef\nghi", '1.png', '').exactly(1)
+        r = @p.store_picture(@imager, '1.png')
+      end
+      it '画像ファイルの垂直反転への保存が1回呼ばれる' do
+        PictureIO.picture_io.should_receive(:put).with("cba\nfed\nihg", '1.png', 'v').exactly(1)
+        r = @p.store_picture(@imager, '1.png')
+      end
+      it '画像ファイルの水平反転への保存が1回呼ばれる' do
+        PictureIO.picture_io.should_receive(:put).with("ghi\ndef\nabc", '1.png', 'h').exactly(1)
+        r = @p.store_picture(@imager, '1.png')
+      end
+      it '画像ファイルの垂直水平反転への保存が1回呼ばれる' do
+        PictureIO.picture_io.should_receive(:put).with("ihg\nfed\ncba", '1.png', 'vh').exactly(1)
+        r = @p.store_picture(@imager, '1.png')
+      end
     end
     context 'つつがなく終わるとき' do
       before do
-        #すべての処理を正常パターンで通過させ、保存機能をチェックする。\r
+        #すべての処理を正常パターンで通過させ、保存機能をチェックする。
         PictureIO.picture_io.stub(:put).with(any_args).and_return(true)
       end
       it 'Trueを返す' do
-        res = @p.store_picture(Mgk.new)\r
-        res.should be_true\r
-      end\r
+        r = @p.store_picture(@imager, '1.png')
+        r.should be_true
+      end
     end
     context '例外ケース' do
       before do
         PictureIO.picture_io.stub(:put).with(any_args).and_return(false)
       end
       it 'Falseを返す' do
-        res = @p.store_picture(Mgk.new)\r
-        res.should be_false\r
-      end\r
+        r = @p.store_picture(@imager, '1.png')
+        r.should be_false
+      end
     end
     
   end
   
+  describe '墨塗に於いて' do
+    before do
+      @p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id, :ext => 'png'
+    end
+    context '事前チェック' do
+      before do
+        @imager = ImagerTest.load "abc\ndef\nghi"
+        Picture.any_instance.stub(:store).with(any_args).and_return(true)
+        PettanImager.stub(:load).with(any_args).and_return(@imager)
+      end
+      it '画像ライブラリにロードを依頼している' do
+        PettanImager.should_receive(:load).with(any_args).exactly(1)
+        r = @p.unpublish
+      end
+      it '自身に作成を依頼している' do
+        Picture.any_instance.should_receive(:store).with(any_args).exactly(1)
+        r = @p.unpublish
+      end
+    end
+    context 'つつがなく終わるとき' do
+      before do
+        Picture.any_instance.stub(:store).with(any_args).and_return(true)
+      end
+      it 'Trueを返す' do
+        r = @p.unpublish
+        r.should be_true
+      end
+    end
+    #例外ケース
+    context '画像ライブラリのロードに失敗したとき' do
+      before do
+        PettanImager.stub(:load).and_return(false)
+      end
+      it 'Falseを返す' do
+        r = @p.unpublish
+        r.should be_false
+      end
+    end
+    context '作成に失敗したとき' do
+      before do
+        Picture.any_instance.stub(:store).with(any_args).and_return(false)
+      end
+      it 'Falseを返す' do
+        r = @p.unpublish
+        r.should be_false
+      end
+    end
+  end
+  
   describe 'フラグ展開に於いて' do
     before do
-      @p = Factory.build :picture, :original_picture_id => @op.id, :license_id => @license.id,
+      @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id,
         :settings => "{\"open\": 1, \"commercial\": 2, \"official\": 3, \"attribution\": 4, \"derive\": 5, \"thumbnail\": 6, \"gif_convert\": 7, \"reverse\": 8, \"resize\": 9, \"sync_vh\": 10, \"overlap\": 11}"
     end
     context 'json展開チェック' do
       it '展開してなければ展開して@flagsに保管する' do
         @p.flags.should_not be_nil
       end
-      it '展開できなければnilのまま' do
+      it '展開できなければ{}' do
         @p.settings += '}'
-        @p.flags.should be_nil
+        @p.flags.is_a?(Hash).should be_true
+        @p.flags.empty?.should be_true
       end
     end
     context 'openについて' do
@@ -721,5 +1120,79 @@ describe Picture do
       end
     end
   end
-\r
+
+  describe 'クレジットデータに於いて' do
+    before do
+      @op = FactoryGirl.create :original_picture, :artist_id => @artist.id
+      @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id, :credit => '{"system_picture_id": 2}'
+    end
+    it 'system_picture_idが入っている' do
+      res = @p.credit_data
+      res["system_picture_id"].should eq 2
+    end
+  end
+  
+  describe 'エクスポートに於いて' do
+    before do
+      @op = FactoryGirl.create :original_picture, :artist_id => @artist.id
+      @p = FactoryGirl.create :picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :revision => 0
+      @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :picture_id => @p.id
+      @p2 = FactoryGirl.create :picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :revision => 1, :updated_at => Time.now + 1000
+      #開始日時以前の実素材
+      @old_op = FactoryGirl.create :original_picture, :artist_id => @artist.id
+      @old_p = FactoryGirl.create :picture, :artist_id => @artist.id, :original_picture_id => @old_op.id, :license_id => @license.id, :revision => 0, :updated_at => Time.now - 1000
+      @old_rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :original_picture_id => @old_op.id, :license_id => @license.id, :picture_id => @old_p.id
+      #他人の実素材
+      @other_op = FactoryGirl.create :original_picture, :artist_id => @other_artist.id
+      @other_p = FactoryGirl.create :picture, :artist_id => @other_artist.id, :original_picture_id => @other_op.id, :license_id => @license.id, :revision => 0, :updated_at => Time.now + 100
+      @other_rp = FactoryGirl.create :resource_picture, :artist_id => @other_artist.id, :original_picture_id => @other_op.id, :license_id => @license.id, :picture_id => @other_p.id
+      #貸手からの実素材排除
+      @outer_artist = FactoryGirl.create :artist_yas, :author_id => nil
+      @outer_op = FactoryGirl.create :original_picture, :artist_id => @outer_artist.id
+      @outer_p = FactoryGirl.create :picture, :artist_id => @outer_artist.id, :original_picture_id => @outer_op.id, :license_id => @license.id, :revision => 0
+      @outer_rp = FactoryGirl.create :resource_picture, :artist_id => @outer_artist.id, :original_picture_id => @outer_op.id, :license_id => @license.id, :picture_id => @outer_p.id
+    end
+    context 'つつがなく終わるとき' do
+      it '開始日時が省略された場合はすべての内実素材を返す' do
+        r = Picture.export 
+        r.should eq [@p2, @other_p, @p, @old_p]
+      end
+      it '開始日時以降に更新された内実素材を返す' do
+        r = Picture.export @p.updated_at - 100
+        r.should eq [@p2, @other_p, @p]
+      end
+    end
+  end
+  
+  describe 'リストのjson化に於いて' do
+    before do
+      @op = FactoryGirl.create :original_picture, :artist_id => @artist.id
+      @p = FactoryGirl.create :picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :revision => 0
+      @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :original_picture_id => @op.id, :license_id => @license.id, :picture_id => @p.id
+      @other_op = FactoryGirl.create :original_picture, :artist_id => @other_artist.id
+      @other_p = FactoryGirl.create :picture, :artist_id => @other_artist.id, :original_picture_id => @other_op.id, :license_id => @license.id, :revision => 0, :updated_at => Time.now + 100
+      @other_rp = FactoryGirl.create :resource_picture, :artist_id => @other_artist.id, :original_picture_id => @other_op.id, :license_id => @license.id, :picture_id => @other_p.id
+      Picture.any_instance.stub(:restore).with(any_args).and_return('picture binary data')
+    end
+    context 'つつがなく終わるとき' do
+      it 'json文字列を返す' do
+        r = Picture.list_as_json_text Picture.all 
+        lambda {
+          j = JSON.parse r
+        }.should_not raise_error(JSON::ParserError)
+      end
+      it '実素材リストを返す' do
+        r = Picture.list_as_json_text Picture.all 
+        j = JSON.parse r
+        j.size.should eq 2
+      end
+      it '各実素材に画像データを添えて返す' do
+        r = Picture.list_as_json_text Picture.all 
+        j = JSON.parse r
+        j.first['picture_data'].should_not be_nil
+        j.last['picture_data'].should_not be_nil
+      end
+    end
+  end
+  
 end