class ComicsController < ApplicationController
+ layout 'test' if Pettanr::TestLayout
if Const.run_mode == 0
before_filter :authenticate_user!, :only => [:new, :create, :edit, :update, :destroy]
else
end
end
- def play
- c = Comic.show(params[:id], @author)
- cnt = Panel.count(:conditions => ['comic_id = ?', c.id]).to_i
- @offset = Comic.offset cnt, params[:offset]
- @panel_count = Comic.panel_count cnt, params[:count]
- @comic = Comic.play(params[:id])
- respond_to do |format|
- format.html # index.html.erb
- format.json {
- render :json => @comic.to_json_play
- }
- format.jsonp {
- render :json => "callback(" + @comic.to_json_play + ");"
- }
- end
- end
-
def list
@comics = Comic.all
class StoriesController < ApplicationController
+ layout 'test' if Pettanr::TestLayout
+ if Const.run_mode == 0
+ before_filter :authenticate_user!, :only => [:new, :create, :edit, :update, :destroy]
+ else
+ before_filter :authenticate_user!, :only => [:index, :show, :new, :create, :edit, :update, :destroy]
+ end
+ before_filter :authenticate_admin!, :only => [:list, :browse]
+
+ def show
+ @comic = Comic.show(params[:id], @author)
+ cnt = Story.count(:conditions => ['comic_id = ?', @comic.id]).to_i
+ @offset = Story.offset cnt, params[:offset]
+ @panel_count = Story.panel_count cnt, params[:count]
+ @stories = Story.list(@comic, @author, @offset, @panel_count)
+ respond_to do |format|
+ format.html # index.html.erb
+ format.json {
+ render :json => @stories.to_json_list
+ }
+ format.jsonp {
+ render :json => "callback(" + @stories.to_json_list + ");"
+ }
+ end
+ end
+
+ def list
+ @stories = Story.all
+
+ respond_to do |format|
+ format.html { render layout: 'system' }# index.html.erb
+ format.json { render json: @stories }
+ end
+ end
+
+ def browse
+ @story = Story.find(params[:id])
+
+ respond_to do |format|
+ format.html { render layout: 'system' } # show.html.erb
+ format.json { render json: @story }
+ end
+ end
+
+ # GET /stories/new
+ # GET /stories/new.js
+ # GET /stories/new.json
+ def new
+ @story = Story.new
+ @story.supply_default @author
+ @form_opt = {}
+ respond_to do |format|
+ format.html # new.html.erb
+ format.js { @form_opt = {:remote => true} ; render action: "new" }
+ format.json { render json: @story }
+ end
+ end
+
+ # GET /stories/1/edit
+ # GET /stories/1.js/edit
+ def edit
+ @story = Story.show(params[:id], @author)
+ respond_to do |format|
+ format.html
+ format.js
+ end
+ end
+
+ # POST /stories
+ # POST /stories.js
+ # POST /stories.json
+ def create
+ @story = Story.new
+ @story.supply_default @author
+ @story.attributes = params[:story]
+
+ respond_to do |format|
+ if @story.store
+ format.html { redirect_to action: :show, id: @story.comic_id }
+ format.js { redirect_to action: :show, id: @story.comic_id }
+ format.json { render json: @story.to_json() }
+ else
+ format.html { render action: "new" }
+ format.json { render json: @story.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # PUT /stories/1
+ # PUT /stories/1.js
+ # PUT /stories/1.json
+ def update
+ @story = Story.show(params[:id], @author)
+ @story.author_id = @author.id
+ ot = @story.t
+ @story.attributes = params[:story]
+ respond_to do |format|
+ if @story.store ot
+ format.html { redirect_to action: :show, id: @story.comic_id }
+ format.js { redirect_to action: :show, id: @story.comic_id }
+ format.json { head :ok }
+ else
+ format.html { render action: "edit" }
+ format.json { render json: @story.errors, status: :unprocessable_entity }
+ end
+ end
+ end
+
+ # DELETE /stories/1
+ # DELETE /stories/1.js
+ # DELETE /stories/1.json
+ def destroy
+ @story = Story.show(params[:id], @author)
+ @story.destroy_and_shorten
+ respond_to do |format|
+ format.html { redirect_to story_path(@story.comic) }
+ format.json { head :ok }
+ end
+ end
end
{:include => {:stories => {:panel => {}}, :author => {}}}
end
- def self.play cid, opt = {}
- Comic.find(cid, include: [
- :author,
- :panels => [
- :panel_pictures => :resource_picture,
- :speech_balloons =>{:balloons => {}, :speeches => {}}
- ]
- ], order: 'panels.t')
- end
-
- def to_json_play
- self.to_json( :include => {:author => {}, :panels => {:methods => :panel_element}})
- end
-
def self.visible_count
Comic.count 'visible > 0'
end
self.author_id == author.id
end
+ def usable? au
+ own? au
+ end
+
def publish?
self.publish > 0
end
validates :t, :presence => true, :numericality => {:greater_than_or_equal_to => 0}
def supply_default au
+ self.t = nil
return false unless au
self.author_id = au.id
end
+ def own? author
+ return false unless author
+ self.author_id == author.id
+ end
+
+ def self.show sid, au = nil
+ res = Story.find sid
+ if au
+ raise ActiveRecord::Forbidden unless res.own?(au)
+ end
+ res
+ end
+
def self.new_t comic_id
r = Story.max_t(comic_id)
r.blank? ? 0 : r.to_i + 1
end
end
+ def allow?
+ c = self.comic
+ pl = self.panel
+ c and c.own?(self.author) and pl and pl.usable?(self.author)
+ end
+
def store old_t = nil
res = false
+ raise ActiveRecord::Forbidden unless self.allow?
Story.transaction do
self.rotate old_t
res = self.save
- unless Story.validate_t(self)
- res = false
+ raise ActiveRecord::Rollback unless res
+ res = Story.validate_t(self)
+ unless res
+ self.errors.add :t, 'unserialized'
raise ActiveRecord::Rollback
end
end
res
end
- def move_to new_t
- return true if self.t == new_t
- if self.t > new_t
- Panel.update_all('t = t + 1', ['comic_id = ? and (t >= ? and t < ?)', self.comic_id, new_t, self.t])
- else
- nf = Panel.find_t(self.comic_id, new_t)
- max_t = Panel.max_t.to_i self.comic_id
- new_t = max_t if new_t > max_t
- Panel.update_all('t = t - 1', ['comic_id = ? and (t > ? and t <= ?)', self.comic_id, self.t, new_t])
+ def destroy_and_shorten
+ Story.transaction do
+ Story.update_all('t = t - 1', ['comic_id = ? and (t > ?)', self.comic_id, self.t])
+ raise ActiveRecord::Rollback unless self.destroy
end
- self.t = new_t
- self.save
end
- def destroy_and_shorten
- Panel.update_all('t = t - 1', ['comic_id = ? and (t > ?)', self.comic_id, self.t])
- self.destroy
+ def self.default_panel_size
+ 30
+ end
+
+ def self.max_panel_size
+ 200
end
+ def self.offset cnt, prm = nil
+ offset = prm.to_i
+ offset = cnt - 1 if offset >= cnt
+ offset = cnt - offset.abs if offset < 0
+ offset = 0 if offset < 0
+ offset
+ end
+
+ def self.panel_count cnt, prm = self.default_panel_size
+ count = prm.to_i
+ count = self.max_panel_size if count > self.max_panel_size
+ count = self.default_panel_size if count < 1
+ count
+ end
+
+ def self.list comic, author, offset = 0, limit = Story.default_panel_size
+ opt = self.list_opt
+ opt.merge!({:conditions => ['stories.comic_id = ?', comic.id], :order => 'stories.t', :offset => offset, :limit => limit})
+ Story.find(:all, opt)
+ end
+
+ def self.list_opt
+ {:include => {
+ :author => {},
+ :comic => {
+ :author => {}
+ },
+ :panel => {
+ :author => {},
+ :panel_pictures => {:resource_picture => {:artist => {}}},
+ :speech_balloons =>{:balloons => {}, :speeches => {}}
+ }
+ }}
+ end
+
+ def self.list_json_opt
+ {:include => {
+ :author => {},
+ :comic => {
+ :author => {}
+ },
+ :panel => {
+ :author => {},
+ :panel_pictures => {:resource_picture => {:artist => {}}},
+ :speech_balloons =>{:balloons => {}, :speeches => {}}
+ }
+ }}
+ end
+
+ def to_json_list
+ self.to_json( :include => {:author => {}, :panels => {:methods => :panel_element}})
+ end
+
+
end
<%= f.label :visible %><br />
<%= f.collection_select :visible, [['only me', 0], ['everyone', 3]], :last, :first, :html => {:selected => @comic.visible} %>
</div>
- <div class="field">
- <%= f.label :editable %><br />
- <%= f.collection_select :editable, [['only me', 0], ['everyone', 3]], :last, :first, :html => {:selected => @comic.editable} %>
- </div>
<div class="actions">
<%= f.submit %>
</p>
<p>
- <b>editable:</b>
- <%= @comic.editable %>
-</p>
-
-<p>
<b>author_id:</b>
<%= @comic.author_id %>
</p>
<% @comics.each do |comic| %>
<div>
<div>
- <%= link_to h(comic.title), :action => :play, :id => comic.id %>
- 一般投稿:<%= comic.disp_editable %>
+ <%= link_to h(comic.title), :controller => 'stories', :action => :show, :id => comic.id %>
</div>
<div>
作家:<%= h comic.author.name %>
<th>width</th>
<th>height</th>
<th>visible</th>
- <th>editable</th>
<th>author_id</th>
<th>created_at</th>
<th>updated_at</th>
<td><%= comic.width %></td>
<td><%= comic.height %></td>
<td><%= comic.visible %></td>
- <td><%= comic.editable %></td>
<td><%= link_to comic.author_id, :controller => '/authors', :action => :browse, :id => comic.author_id %></td>
<td><%= comic.created_at %></td>
<td><%= comic.updated_at %></td>
</p>
<p>
- <b>editable:</b>
- <%= @comic.editable %>
-</p>
-
-<p>
<b>author_id:</b>
<%= @comic.author_id %>
</p>
-<span>
-t:<%= @panel.t %>
-</span>
<div class="panel" style="width:<%= @panel.width %>px;height:<%= @panel.height %>px;overflow:hidden; border:solid black <%= @panel.border %>px; background:white;">
<% @panel.each_element do |elm| %>
<% if elm.kind_of?(PanelPicture) %>
<% end %>
</div>
<span>
-Comic:<%= @panel.comic_id %>
-</span>
-<span>
-resource_picture:<%= @panel.resource_picture_id %>
-</span>
-<span>
Width:<%= @panel.width %>
</span>
<span>
Height:<%= @panel.height %>
</span>
-<%= form_for(@panel) do |f| %>
- <%= f.submit 'move to' %>
- <%= f.number_field :t %>
-<% end %>
-<%= button_to 'Destroy', @panel, confirm: 'Are you sure?', method: :delete %>
<h1>Listing panels 最近の投稿</h1>
<% @panels.each do |panel| %>
<div>
- <%= link_to h(panel.comic.title), panel.comic %>t:<%= panel.t %>
<div class="panel" style="width:<%= panel.width %>px;height:<%= panel.height %>px;overflow:hidden; border:solid black <%= panel.border %>px; background:white;">
<% panel.panel_pictures.each do |panel_picture| %>
<div id="vPicture<%= panel_picture.id -%>" class="panel_picture" style="position:relative; top:<%= panel_picture.y -%>px; left:<%= panel_picture.x -%>px; z-index:<%= panel_picture.z -%>; ">
<%= h panel.author.name %> <%= panel.updated_at %>
</div>
<% end %>
-<%= link_to 'open form', new_panel_path, :remote => true %>\r
- <div id="newpanel">\r
- uploader\r
- </div>\r
+<%= link_to 'open form', new_panel_path, :remote => true %>
+ <div id="newpanel">
+ uploader
+ </div>
<h1>Listing panels</h1>
-<%= link_to 'open form', new_panel_path, :remote => true %>\r
- <div id="newpanel">\r
- uploader\r
- </div>\r
+<%= link_to 'open form', new_panel_path, :remote => true %>
+ <div id="newpanel">
+ uploader
+ </div>
<table>
<tr>
<th>id</th>
- <th>Comic</th>
<th>Width</th>
<th>Height</th>
<th>Border</th>
<th>x</th>
<th>y</th>
<th>z</th>
- <th>t</th>
+ <th>publish</th>
<th>author_id</th>
<th>created_at</th>
<th>updated_at</th>
<% @panels.each do |panel| %>
<tr>
<td><%= link_to panel.id, :action => :browse, :id => panel.id %></td>
- <td><%= link_to panel.comic_id, :controller => 'comics', :action => :browse, :id => panel.comic_id %></td>
<td><%= panel.width %></td>
<td><%= panel.height %></td>
<td><%= panel.border %></td>
<td><%= panel.x %></td>
<td><%= panel.y %></td>
<td><%= panel.z %></td>
- <td><%= panel.t %></td>
+ <td><%= panel.publish %></td>
<td><%= link_to panel.author_id, :controller => '/authors', :action => :browse, :id => panel.author_id %></td>
<td><%= panel.created_at %></td>
<td><%= panel.updated_at %></td>
--- /dev/null
+<%= form_for(@story) do |f| %>
+ <% if @story.errors.any? %>
+ <div id="error_explanation">
+ <h2><%= pluralize(@story.errors.count, "error") %> prohibited this comic from being saved:</h2>
+
+ <ul>
+ <% @story.errors.full_messages.each do |msg| %>
+ <li><%= msg %></li>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+
+ <div class="field">
+ <%= f.hidden_field :comic_id %>
+ </div>
+ <div class="field">
+ <%= f.number_field :t %>
+ </div>
+ <div class="field">
+ <%= f.hidden_field :panel_id %>
+ </div>
+
+ <div class="actions">
+ <%= f.submit %>
+ </div>
+<% end %>
+<%= button_to 'Destroy', @story.panel, confirm: 'Are you sure?', method: :delete %>
--- /dev/null
+<%= form_for(@story, @form_opt) do |f| %>
+ <% if @story.errors.any? %>
+ <div id="error_explanation">
+ <h2><%= pluralize(@story.errors.count, "error") %> prohibited this comic from being saved:</h2>
+
+ <ul>
+ <% @story.errors.full_messages.each do |msg| %>
+ <li><%= msg %></li>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+
+ <div class="field">
+ <%= f.number_field :comic_id %>
+ </div>
+ <div class="field">
+ <%= f.number_field :t %>
+ </div>
+ <div class="field">
+ <%= f.number_field :panel_id %>
+ </div>
+
+ <div class="actions">
+ <%= f.submit %>
+ </div>
+<% end %>
--- /dev/null
+<p id="notice"><%= notice %></p>
+
+<p>
+ <b>comic_id:</b>
+ <%= @story.comic_id %>
+</p>
+
+<p>
+ <b>panel_id:</b>
+ <%= @story.panel_id %>
+</p>
+
+<p>
+ <b>t:</b>
+ <%= @story.t %>
+</p>
+
+<p>
+ <b>author_id:</b>
+ <%= @story.author_id %>
+</p>
+
+<p>
+ <b>updated_at:</b>
+ <%= @story.updated_at %>
+</p>
+
+<%= link_to 'Back', :action => :list %>
--- /dev/null
+<%= render 'editform' %>
--- /dev/null
+$("#story-update-<%= @story.id -%>").html("<%= escape_javascript(render('editform')) -%>");
--- /dev/null
+<h1>Listing Story</h1>
+
+<table>
+ <tr>
+ <th>id</th>
+ <th>comic_id</th>
+ <th>panel_id</th>
+ <th>t</th>
+ <th>author_id</th>
+ <th>created_at</th>
+ <th>updated_at</th>
+ <th></th>
+ </tr>
+
+<% @stories.each do |story| %>
+ <tr>
+ <td><%= link_to story.id, :action => :browse, :id => story.id %></td>
+ <td><%= story.comic_id %></td>
+ <td><%= story.panel_id %></td>
+ <td><%= story.t %></td>
+ <td><%= link_to story.author_id, :controller => '/authors', :action => :browse, :id => story.author_id %></td>
+ <td><%= story.created_at %></td>
+ <td><%= story.updated_at %></td>
+ <td>
+ </td>
+ </tr>
+<% end %>
+</table>
+
--- /dev/null
+<%= render 'newform' %>
--- /dev/null
+$("#story-create").html("<%= escape_javascript(render('newform')) -%>");
--- /dev/null
+<h1><%= h @comic.title %></h1>
+
+<% @stories.each do |story| %>
+ <% @story = story %>
+ <% @panel = story.panel %>
+ <%= render 'panels/standard' %>
+ <% if story.author.id == @author.id -%>
+ <span>
+ t:<%= story.t %>
+ </span>
+<%= button_to 'Destroy', @story, confirm: 'Are you sure?', method: :delete %>
+ <%= render 'editform' %>
+ <%= link_to 'open js', edit_story_path(story), :remote => true %>
+ <div id="story-update-<%= @story.id -%>">
+ t
+ </div>
+ <% end -%>
+<% end %>
+<% if @comic.author.id == @author.id -%>
+ <%= link_to 'add panel', new_story_path, :remote => true %>
+ <div id="story-create">
+ t
+ </div>
+<% end %>
+<%= link_to 'Back', comics_path %>
</tr>
<tr>
<td>
+ <%= link_to 'stories', :controller => 'stories', :action => :list %>
+ </td>
+ </tr>
+ <tr>
+ <td>
<%= link_to 'original_pictures', :controller => 'original_pictures', :action => :list %>
</td>
</tr>
end
end
resources :original_pictures do
+ new do
+ get :new
+ end
collection do
get :index
get :show
- get :new
post :create
get :list
get :browse
delete :destroy
end
end
+ resources :stories do
+ new do
+ get :new
+ end
+ collection do
+ post :create
+ get :list
+ get :browse
+ end
+ member do
+ get :show
+ put :update
+ delete :destroy
+ end
+ end
resources :comics do #, except: [:new, :edit]
+ new do
+ get :new
+ end
collection do
get :index
get :show
--- /dev/null
+if ARGV.size < 2\r
+ puts 'create.rb subdir controller {filename=create.json}'\r
+ exit\r
+end\r
+domain = 'http://localhost:3000'\r
+user = ARGV[0].to_s\r
+ctl = ARGV[1]\r
+f = ARGV[2] ? ARGV[2].to_s+'_create' : 'create'\r
+path = File.expand_path(File.dirname(__FILE__))\r
+filename = path + "/#{user}/#{ctl}/#{f}.json"\r
+\r
+cmd = "curl -d @#{filename} #{domain}/#{ctl}.json -X POST -H \"Content-Type: application/json\""\r
+puts cmd\r
+exec cmd\r
--- /dev/null
+if ARGV.size < 2\r
+ puts 'reauth.rb subdir new_auth_token'\r
+ exit\r
+end\r
+require 'json'\r
+path = File.expand_path(File.dirname(__FILE__)) + '/' + (ARGV[0].to_s + '/' + '*')\r
+puts 'path:'\r
+puts path\r
+Dir.glob path do |filename|\r
+ if File.directory?(filename)\r
+ puts 'search dir:'\r
+ puts filename\r
+ Dir.glob filename + '/*' do |filename2|\r
+ d = nil\r
+ puts 'replace:'\r
+ puts filename2\r
+ File.open(filename2, 'rb') do |f|\r
+ d = f.read\r
+ end\r
+ j = JSON.parse d\r
+ ot = j["auth_token"]\r
+ b = d.gsub /#{ot}/, ARGV[1].to_s\r
+ File.open(filename2, 'wb') do |f|\r
+ f.write b\r
+ end\r
+ end\r
+ else\r
+ puts 'ignore file:'\r
+ puts filename\r
+ end\r
+end\r
--- /dev/null
+{\r
+ "comic": {\r
+ "title": "コミック作るテスト",\r
+ "width": 400,\r
+ "height": 200,\r
+ "visible": 3\r
+ },\r
+ "auth_token": "Qr2cveaLKqMHA8dME7CN"\r
+}
\ No newline at end of file
--- /dev/null
+{\r
+ "original_picture": {\r
+ "file": \r
+"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" },\r
+ "auth_token": "Qr2cveaLKqMHA8dME7CN"\r
+}
\ No newline at end of file
--- /dev/null
+{\r
+ "panel": {\r
+ "width": 400,\r
+ "height": 200,\r
+ "border": 1,\r
+ "x": 0,\r
+ "y": 0,\r
+ "z": 1,\r
+ "publish": 1,\r
+ "panel_pictures_attributes": {\r
+ "new1": {\r
+ "resource_picture_id": 3,\r
+ "x": 10,\r
+ "y": 135,\r
+ "z": 3,\r
+ "t": 0,\r
+ "width": 100,\r
+ "height": 103\r
+ }\r
+ }\r
+ },\r
+ "auth_token": "Qr2cveaLKqMHA8dME7CN"\r
+}
\ No newline at end of file
--- /dev/null
+{\r
+ "story": {\r
+ "comic_id": 1,\r
+ "panel_id": 1\r
+ },\r
+ "auth_token": "Qr2cveaLKqMHA8dME7CN"\r
+}
\ No newline at end of file
--- /dev/null
+if ARGV.size < 2\r
+ puts 'update.rb subdir controller {filename=update.json}'\r
+ exit\r
+end\r
+domain = 'http://localhost:3000'\r
+user = ARGV[0].to_s\r
+ctl = ARGV[1]\r
+f = ARGV[2] ? ARGV[2].to_s+'_update' : 'update'\r
+path = File.expand_path(File.dirname(__FILE__))\r
+filename = path + "/#{user}/#{ctl}/#{f}.json"\r
+\r
+cmd = "curl -d @#{filename} #{domain}/#{ctl}.json -X PUT -H \"Content-Type: application/json\""\r
+puts cmd\r
+exec cmd\r
require 'spec_helper'
#ストーリー
describe StoriesController do
+ before do
+ Factory :admin
+ @license = Factory :license
+ @user = Factory :user_yas
+ @author = @user.author #ユーザ作成時に連動して作成される
+ @comic = Factory :comic, :author_id => @user.author.id
+ @panel = Factory :panel, :author_id => @author.id
+ end
+
describe '閲覧に於いて' do
before do
- @comic = Factory :comic, :author_id => @user.author.id
+ @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
Comic.stub(:show).and_return(@comic)
sign_in @user
end
context '事前チェックする' do
+ end
+ context 'つつがなく終わるとき' do
+ end
+ context '作家権限がないとき' do
+ end
+ end
+
+ describe '新規作成フォーム表示に於いて' do
+ before do
+ sign_in @user
+ end
+ context 'つつがなく終わるとき' do
+ it 'ステータスコード200 OKを返す' do
+ get :new
+ response.should be_success
+ end
+ it '@storyに新規データを用意している' do
+ get :new
+ assigns(:story).should be_a_new(Story)
+ end
+ it 'コマモデルにデフォルト値補充を依頼している' do
+ Story.any_instance.should_receive(:supply_default).exactly(1)
+ get :new
+ end
+ context 'html形式' do
+ it 'newテンプレートを描画する' do
+ get :new
+ response.should render_template("new")
+ end
+ end
+ context 'js形式' do
+ it 'new.jsテンプレートを描画する' do
+ get :new, :format => :js
+ response.should render_template("new")
+ end
+ end
+ end
+ context '作家権限がないとき' do
before do
- Panel.stub(:count).and_return(10)
+ sign_out @user
end
- it '与えられたoffsetがセットされている' do
- get :play, :id => @comic.id, :offset => 7
- assigns(:offset).should eq 7
+ context 'html形式' do
+ it 'ステータスコード302 Foundを返す' do
+ get :new
+ response.status.should eq 302
+ end
+ it 'サインインページへ遷移する' do
+ get :new
+ response.body.should redirect_to '/users/sign_in'
+ end
end
- it '省略されると@offsetに0値が入る' do
- get :play, :id => @comic.id
- assigns(:offset).should eq 0
+ context 'js形式' do
+ it 'ステータスコード401 Unauthorizedを返す' do
+ get :new, :format => :js
+ response.status.should eq 401
+ end
+ it '応答メッセージにUnauthorizedを返す' do
+ get :new, :format => :js
+ response.message.should match(/Unauthorized/)
+ end
end
- it 'コマ数以上が与えられるとコマ数-1が入る' do
- get :play, :id => @comic.id, :offset => 10
- assigns(:offset).should eq 9
+ end
+ end
+
+ describe '新規作成に於いて' do
+ before do
+ @attr = Factory.attributes_for(:story, :t => nil, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id)
+ sign_in @user
+ end
+ context 'つつがなく終わるとき' do
+ it 'モデルに保存依頼する' do
+ Story.any_instance.should_receive(:store).exactly(1)
+ post :create, :story => @attr
end
- it '負の値が与えられると末尾(コマ数)からさかのぼった値が入る' do
- get :play, :id => @comic.id, :offset => -3
- assigns(:offset).should eq 7
+ it "@storyに作成されたコマを保持していて、それがDBにある" do
+ post :create, :story => @attr
+ assigns(:story).should be_a(Story)
+ assigns(:story).should be_persisted
end
- it 'コマ数以上の負の値が与えられると計算できないので0値が入る' do
- get :play, :id => @comic.id, :offset => -13
- assigns(:offset).should eq 0
+ context 'html形式' do
+ it 'ステータスコード302 Foundを返す' do
+ Story.any_instance.stub(:store).and_return(true)
+ post :create, :story => @attr
+ response.status.should eq 302
+ end
+ it 'コミックのストーリー表示へ遷移する' do
+# Story.any_instance.stub(:store).and_return(true)
+ post :create, :story => @attr
+ response.should redirect_to(:action => :show, :id => @attr[:comic_id])
+ end
end
- it '与えられたcountがセットされている' do
- get :play, :id => @comic.id, :count => 18
- assigns(:panel_count).should eq 18
+ context 'js形式' do
+ it 'ステータスコード302 Foundを返す' do
+ Story.any_instance.stub(:store).and_return(true)
+ post :create, :story => @attr, :format => :js
+ response.status.should eq 302
+ end
+ it 'コミックのストーリー表示へ遷移する' do
+# Story.any_instance.stub(:store).and_return(true)
+ post :create, :story => @attr, :format => :js
+ response.should redirect_to(:action => :show, :id => @attr[:comic_id])
+ end
end
- it '省略されると@countにデフォルト値が入る' do
- get :play, :id => @comic.id
- assigns(:panel_count).should eq Comic.default_panel_size
+ context 'json形式' do
+ it 'ステータスコード200 OKを返す' do
+# Story.any_instance.stub(:store).and_return(true)
+ post :create, :story => @attr, :format => :json
+ response.should be_success
+ end
+ it '作成されたコマをjsonデータで返す' do
+ post :create, :story => @attr, :format => :json
+ lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
+ end
+ it 'データがアレになっている' do
+ post :create, :story => @attr, :format => :json
+ json = JSON.parse response.body
+ json["t"].should eq @story.t
+ end
end
- it '最大を超えると@countにデフォルト最大値が入る' do
- get :play, :id => @comic.id, :count => 1500
- assigns(:panel_count).should eq Comic.max_panel_size
+ end
+ context '作家権限がないとき' do
+ before do
+ sign_out @user
end
- it '不正な値が入ると@countにデフォルト最大値が入る' do
- get :play, :id => @comic.id, :page_size => 0
- assigns(:panel_count).should eq Comic.default_panel_size
+ context 'html形式' do
+ it 'ステータスコード302 Foundを返す' do
+ post :create, :story => @attr
+ response.status.should eq 302
+ end
+ it 'サインインページへ遷移する' do
+ post :create, :story => @attr
+ response.body.should redirect_to '/users/sign_in'
+ end
+ end
+ context 'json形式' do
+ it 'ステータスコード401 Unauthorizedを返す' do
+ post :create, :story => @attr, :format => :json
+ response.status.should eq 401
+ end
+ it '応答メッセージにUnauthorizedを返す' do
+ post :create, :story => @attr, :format => :json
+ response.message.should match(/Unauthorized/)
+ end
end
end
+ context '検証、保存に失敗した' do
+ before do
+ Story.any_instance.stub(:store).and_return(false)
+ end
+ it "未保存のコマを保持している" do
+ post :create, :story => @attr
+ assigns(:story).should be_a_new(Story)
+ end
+ context 'html形式' do
+ it 'ステータスコード200 OKを返す' do
+ post :create, :story => @attr
+ response.status.should eq 200
+ end
+ it '新規ページを描画する' do
+ post :create, :story => @attr
+ response.should render_template("new")
+ end
+ end
+ context 'json形式' do
+ it 'ステータスコード422 unprocessable_entity を返す' do
+ post :create, :story => @attr, :format => :json
+ response.status.should eq 422
+ end
+ it '応答メッセージUnprocessable Entityを返す' do
+ post :create, :story => @attr, :format => :json
+ response.message.should match(/Unprocessable/)
+ end
+ end
+ end
+ end
+
+ describe '編集フォーム表示に於いて' do
+ before do
+ @story = Factory :story, :author_id => @author.id
+ sign_in @user
+ Story.stub(:show).and_return(@story)
+ end
context 'つつがなく終わるとき' do
it 'ステータスコード200 OKを返す' do
- get :play, :id => @comic.id
- response.should be_success
+ get :edit, :id => @story.id
+ response.should be_success
end
- it 'ã\82³ã\83\9fã\83\83ã\82¯モデルに単体取得を問い合わせている' do
- Comic.should_receive(:show).exactly(1)
- get :play, :id => @comic.id
+ it 'ã\82³ã\83\9eモデルに単体取得を問い合わせている' do
+ Story.should_receive(:show).exactly(1)
+ get :edit, :id => @story.id
end
- it '@comicにアレを取得している' do
- get :play, :id => @comic.id
- assigns(:comic).id.should eq(@comic.id)
+ it '@storyにデータを用意している' do
+ get :edit, :id => @story.id
+ assigns(:story).should eq @story
end
context 'html形式' do
- it 'playテンプレートを描画する' do
- get :play, :id => @comic.id
- response.should render_template("play")
+ it 'editテンプレートを描画する' do
+ get :edit, :id => @story.id
+ response.should render_template("edit")
end
end
- context 'json形式' do
- it 'jsonデータを返す' do
- get :play, :id => @comic.id, :format => :json
- lambda{JSON.parse(response.body)}.should_not raise_error(JSON::ParserError)
+ context 'js形式' do
+ it 'edit.jsテンプレートを描画する' do
+ get :edit, :id => @story.id, :format => :js
+ response.should render_template("edit")
end
- it 'データがアレになっている' do
- get :play, :id => @comic.id, :format => :json
- json = JSON.parse response.body
- json["title"].should match(/normal/)
+ end
+ end
+ context '作家権限がないとき' do
+ before do
+ sign_out @user
+ end
+ context 'html形式' do
+ it 'ステータスコード302 Foundを返す' do
+ get :edit, :id => @story.id
+ response.status.should eq 302
+ end
+ it 'サインインページへ遷移する' do
+ get :edit, :id => @story.id
+ response.body.should redirect_to '/users/sign_in'
+ end
+ end
+ context 'js形式' do
+ it 'ステータスコード401 Unauthorizedを返す' do
+ get :edit, :id => @story.id, :format => :js
+ response.status.should eq 401
+ end
+ it '応答メッセージにUnauthorizedを返す' do
+ get :edit, :id => @story.id, :format => :js
+ response.message.should match(/Unauthorized/)
+ end
+ end
+ end
+ end
+
+ describe '更新に於いて' do
+ before do
+ @story = Factory :story, :author_id => @user.author.id
+ @attr = Factory.attributes_for(:story, :author_id => @author.id)
+ sign_in @user
+ end
+ context 'つつがなく終わるとき' do
+ it 'モデルに取得依頼する' do
+ Story.stub(:show).with(any_args).and_return(@story)
+ Story.should_receive(:show).exactly(1)
+ put :update, :id => @story.id, :story => @attr
+ end
+ it 'モデルに保存依頼する' do
+ Story.any_instance.should_receive(:store).exactly(1)
+ put :update, :id => @story.id, :story => @attr
+ end
+ it "@storyに作成されたストーリーを保持していて、それがDBにある" do
+ put :update, :id => @story.id, :story => @attr
+ assigns(:story).should be_a(Story)
+ assigns(:story).should be_persisted
+ end
+ context 'html形式' do
+ it 'ステータスコード302 Foundを返す' do
+ Story.any_instance.stub(:store).and_return(true)
+ put :update, :id => @story.id, :story => @attr
+ response.status.should eq 302
+ end
+ it 'コミックのストーリー表示へ遷移する' do
+# Story.any_instance.stub(:store).and_return(true)
+ put :update, :id => @story.id, :story => @attr
+ response.should redirect_to(:action => :show, :id => @attr[:comic_id])
+ end
+ end
+ context 'json形式' do
+ it 'ステータスコード200 OKを返す' do
+# Story.any_instance.stub(:store).and_return(true)
+ put :update, :id => @story.id, :story => @attr, :format => :json
+ response.should be_success
end
end
end
end
context 'html形式' do
it 'ステータスコード302 Foundを返す' do
- get :play, :id => @comic.id
+ put :update, :id => @story.id, :story => @attr
response.status.should eq 302
end
it 'サインインページへ遷移する' do
- get :play, :id => @comic.id
+ put :update, :id => @story.id, :story => @attr
response.body.should redirect_to '/users/sign_in'
end
end
context 'json形式' do
it 'ステータスコード401 Unauthorizedを返す' do
- get :play, :id => @comic.id, :format => :json
+ put :update, :id => @story.id, :story => @attr, :format => :json
response.status.should eq 401
end
it '応答メッセージにUnauthorizedを返す' do
- get :play, :id => @comic.id, :format => :json
+ put :update, :id => @story.id, :story => @attr, :format => :json
response.message.should match(/Unauthorized/)
end
end
end
+ context '検証、保存に失敗した' do
+ before do
+ Story.any_instance.stub(:store).and_return(false)
+ end
+ it "指定のコマを保持している" do
+ put :update, :id => @story.id, :story => @attr
+ assigns(:story).should eq @story
+ end
+ context 'html形式' do
+ it 'ステータスコード200 OKを返す' do
+ put :update, :id => @story.id, :story => @attr
+ response.status.should eq 200
+ end
+ it '編集ページを描画する' do
+ put :update, :id => @story.id, :story => @attr
+ response.should render_template("edit")
+ end
+ end
+ context 'json形式' do
+ it 'ステータスコード422 unprocessable_entity を返す' do
+ put :update, :id => @story.id, :story => @attr, :format => :json
+ response.status.should eq 422
+ end
+ it '応答メッセージUnprocessable Entityを返す' do
+ put :update, :id => @story.id, :story => @attr, :format => :json
+ response.message.should match(/Unprocessable/)
+ end
+ end
+ end
end
end
@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
end
describe '検証に於いて' do
end
end
+
+ describe '作者判定に於いて' do
+ before do
+ @comic = Factory :comic, :author_id => @author.id
+ @panel = Factory :panel, :author_id => @author.id
+ @story = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id
+ @comico = Factory :comic, :author_id => @other_author.id
+ @panelo = Factory :panel, :author_id => @other_author.id
+ @storyo = Factory :story, :author_id => @other_author.id, :comic_id => @comico.id, :panel_id => @panelo.id
+ end
+ it '自分のストーリーならyes' do
+ @story.own?(@author).should == true
+ end
+ it '他人のストーリーならno' do
+ @storyo.own?(@author).should == false
+ end
+ it '作家が不明ならno' do
+ @story.own?(nil).should == false
+ end
+ end
+ describe '単体取得に於いて' do
+ before do
+ @comic = Factory :comic, :author_id => @author.id
+ @panel = Factory :panel, :author_id => @author.id
+ @story = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id
+ end
+ context 'オーナー指定がないとき' do
+ it '指定のストーリーを返す' do
+ l = Story.show @story.id, @author
+ l.should eq @story
+ end
+ end
+ context 'オーナー指定のとき' do
+ it '指定のストーリーが自分のものならそれを返す' do
+ l = Story.show @story.id, @author
+ l.should eq @story
+ end
+ context '他人のストーリーを開こうとしたとき' do
+ it '403Forbidden例外を返す' do
+ Story.any_instance.stub(:own?).and_return(false)
+ lambda{
+ Story.show @story.id, @author
+ }.should raise_error(ActiveRecord::Forbidden)
+ end
+ end
+ end
+ context '存在しないストーリーを開こうとしたとき' do
+ it '404RecordNotFound例外を返す' do
+ lambda{
+ Story.show 110, @author
+ }.should raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+ end
+
+ describe '一覧取得に於いて' do
+ before do
+ @comic = Factory :comic, :author_id => @author.id
+ @panel = Factory :panel, :author_id => @author.id
+ @story = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id
+ end
+ context 'offset補正について' do
+ it '文字列から数値に変換される' do
+ Story.offset(100, '8').should eq 8
+ end
+ it 'nilの場合は0になる' do
+ Story.offset(100).should eq 0
+ end
+ #投稿されたコマ数以上の値が指定されたときは、最後のコマだけになる
+ #最後のコマとは、コマ数‐1.
+ it '1件のときオフセット1なら0になる' do
+ Story.offset(1, '1').should eq 0
+ end
+ it '5件のときオフセット5なら4になる' do
+ Story.offset(5, '5').should eq 4
+ end
+ # 負の値が指定されたときは、最後のコマから数えてコマを飛ばして表示する。
+ #-4のときは、最後から4つのコマを表示する。
+ it '2件のときオフセット-1なら1になる' do
+ Story.offset(2, '-1').should eq 1
+ end
+ it '5件のときオフセット-2なら3になる' do
+ Story.offset(5, '-2').should eq 3
+ end
+ # 最終的なが負になるなど、不正な値が入ったときは0となる。
+ it '2件のときオフセット-5なら0になる' do
+ Story.offset(2, '-5').should eq 0
+ end
+ end
+ context 'panel_count補正について' do
+ it '文字列から数値に変換される' do
+ Story.panel_count(100, '7').should eq 7
+ end
+ it 'nilの場合はStory.default_panel_sizeになる' do
+ Story.panel_count(100).should eq Story.default_panel_size
+ end
+ it '0以下の場合はStory.default_panel_sizeになる' do
+ Story.panel_count(100, '0').should eq Story.default_panel_size
+ end
+ it 'Story.max_panel_sizeを超えた場合はStory.max_panel_sizeになる' do
+ Story.panel_count(100, '1000').should eq Story.max_panel_size
+ end
+ end
+ it 'リストを返す' do
+ c = Story.list @comic, @author
+ c.should eq [@story]
+ end
+ it 't順で並んでいる' do
+ v = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 1
+ c = Story.list @comic, @author
+ c.should eq [ @story, v]
+ end
+ context 'DBに5件あって1ページの件数を2件に変えたとして' do
+ before do
+ @story2 = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 1
+ @story3 = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 2
+ @story4 = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 3
+ @story5 = Factory :story, :author_id => @author.id, :comic_id => @comic.id, :panel_id => @panel.id, :t => 4
+ end
+ it 'offset=0なら末尾2件を返す' do
+ #時系列で並んでいる
+ c = Story.list( @comic, @author, 0, 2)
+ c.should eq [@story, @story2]
+ end
+ it 'offset=2なら中間2件を返す' do
+ c = Story.list(@comic, @author, 2, 2)
+ c.should eq [@story3, @story4]
+ end
+ it 'offset=4なら先頭1件を返す' do
+ c = Story.list(@comic, @author, 4, 2)
+ c.should eq [@story5]
+ end
+ end
+ end
+ describe 'list関連テーブルプションに於いて' do
+ it 'includeキーを含んでいる' do
+ r = Story.list_opt
+ r.has_key?(:include).should be_true
+ end
+ it '3つの項目を含んでいる' do
+ r = Story.list_opt[:include]
+ r.should have(3).items
+ end
+ it 'コミックを含んでいる' do
+ r = Story.list_opt[:include]
+ r.has_key?(:comic).should be_true
+ end
+ it 'コミックは作家を含んでいる' do
+ r = Story.list_opt[:include]
+ r[:comic].has_key?(:author).should be_true
+ end
+ it '作家を含んでいる' do
+ r = Story.list_opt[:include]
+ r.has_key?(:author).should be_true
+ end
+ it 'コマを含んでいる' do
+ r = Story.list_opt[:include]
+ r.has_key?(:panel).should be_true
+ end
+ it 'コマは作家を含んでいる' do
+ r = Story.list_opt[:include]
+ r[:panel].has_key?(:author).should be_true
+ end
+ it 'コマはコマ絵を含んでいる' do
+ r = Story.list_opt[:include]
+ r[:panel].has_key?(:panel_pictures).should be_true
+ end
+ it 'コマはフキダシを含んでいる' do
+ r = Story.list_opt[:include]
+ r[:panel].has_key?(:speech_balloons).should be_true
+ end
+ end
+ describe 'json一覧出力オプションに於いて' do
+ it 'includeキーを含んでいる' do
+ r = Story.list_json_opt
+ r.has_key?(:include).should be_true
+ end
+ it '3つの項目を含んでいる' do
+ r = Story.list_json_opt[:include]
+ r.should have(3).items
+ end
+ it 'コミックを含んでいる' do
+ r = Story.list_json_opt[:include]
+ r.has_key?(:comic).should be_true
+ end
+ it 'コミックは作家を含んでいる' do
+ r = Story.list_json_opt[:include]
+ r[:comic].has_key?(:author).should be_true
+ end
+ it '作家を含んでいる' do
+ r = Story.list_json_opt[:include]
+ r.has_key?(:author).should be_true
+ end
+ it 'コマを含んでいる' do
+ r = Story.list_json_opt[:include]
+ r.has_key?(:panel).should be_true
+ end
+ it 'コマは作家を含んでいる' do
+ r = Story.list_json_opt[:include]
+ r[:panel].has_key?(:author).should be_true
+ end
+ it 'コマはコマ絵を含んでいる' do
+ r = Story.list_json_opt[:include]
+ r[:panel].has_key?(:panel_pictures).should be_true
+ end
+ it 'コマはフキダシを含んでいる' do
+ r = Story.list_json_opt[:include]
+ r[:panel].has_key?(:speech_balloons).should be_true
+ end
+ end
describe 't補充値に於いて' do
before do
@comic = Factory :comic, :author_id => @author.id
end
end
end
+ describe '編集許可に於いて' do
+ before do
+ @comic = Factory :comic, :author_id => @author.id
+ @panel = Factory :panel, :author_id => @author.id
+ @story = Factory.build :story, :t => nil, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ end
+ context 'つつがなく終わるとき' do
+ it 'trueを返す' do
+ r = @story.allow?
+ r.should be_true
+ end
+ end
+ context 'コミックで引っかかるとき' do
+ it 'falseを返す' do
+ @story.comic_id = nil
+ r = @story.allow?
+ r.should be_false
+ end
+ it 'falseを返す' do
+ Comic.any_instance.stub(:own?).with(any_args).and_return(false)
+ r = @story.allow?
+ r.should be_false
+ end
+ end
+ context 'コマで引っかかるとき' do
+ it 'falseを返す' do
+ @story.panel_id = nil
+ r = @story.allow?
+ r.should be_false
+ end
+ it 'falseを返す' do
+ Panel.any_instance.stub(:usable?).with(any_args).and_return(false)
+ r = @story.allow?
+ r.should be_false
+ end
+ end
+ end
describe '保存に於いて' do
before do
@comic = Factory :comic, :author_id => @author.id
@story = Factory.build :story, :t => nil, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
end
context 'つつがなく終わるとき' do
+ it '編集許可チェックを依頼している' do
+ Story.any_instance.stub(:allow?).with(any_args).and_return(true)
+ Story.any_instance.should_receive(:allow?).with(any_args).exactly(1)
+ r = @story.store
+ end
it '順序入れ替えを依頼している' do
Story.any_instance.stub(:rotate).with(any_args).and_return(0)
Story.any_instance.should_receive(:rotate).with(any_args).exactly(1)
@story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
@story6 = Factory.build :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
end
+ it '既存のt0には変化がない' do
+ @story6.store
+ @story.reload
+ @story.t.should eq 0
+ end
+ it '既存のt1には変化がない' do
+ @story6.store
+ @story2.reload
+ @story2.t.should eq 1
+ end
+ it '既存のt2を3にシフトしている' do
+ @story6.store
+ @story3.reload
+ @story3.t.should eq 3
+ end
+ it '既存のt3を4にシフトしている' do
+ @story6.store
+ @story4.reload
+ @story4.t.should eq 4
+ end
+ it '既存のt5を5にシフトしている' do
+ @story6.store
+ @story5.reload
+ @story5.t.should eq 5
+ end
+ it '新規のt2が作成されている' do
+ @story6.store
+ @story6.reload
+ @story6.t.should eq 2
+ end
it '他のコミックに影響がない' do
+ @ot = @storyc2.t
@story6.store
@storyc2.reload
- @storyc2.t.should eq ot
+ @storyc2.t.should eq @ot
end
end
context 'テーブルに5件(t:0,1,2,3,4)+他のコミック1件で3を1に移動したとき' do
@storyc2.t.should eq 0
end
end
+ #ロールバックテスト。入れ替えが直接DBをいじるので、すべてのケースで確実にロールバックを確認する
+ context 'テーブルに5件(t:0,1,2,3,4)+他のコミック1件で2に挿入したが保存に失敗したとき' do
+ before do
+ Story.any_instance.stub(:save).with(any_args).and_return(false)
+ @comic2 = Factory :comic, :author_id => @author.id
+ @storyc2 = Factory :story, :t => 0, :comic_id => @comic2.id, :panel_id => @panel.id, :author_id => @author.id
+ @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ @story4 = Factory :story, :t => 3, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ @story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ @story6 = Factory.build :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ end
+ it '既存のtに変化がない' do
+ @story6.store
+ @story.reload
+ @story.t.should eq 0
+ @story2.reload
+ @story2.t.should eq 1
+ @story3.reload
+ @story3.t.should eq 2
+ @story4.reload
+ @story4.t.should eq 3
+ @story5.reload
+ @story5.t.should eq 4
+ @storyc2.reload
+ @storyc2.t.should eq 0
+ end
+ it 'falseを返す' do
+ r = @story6.store
+ r.should be_false
+ end
+ end
+ context 'テーブルに5件(t:0,1,2,3,4)+他のコミック1件で3を1に移動したがシリアルチェックに失敗したとき' do
+ before do
+ Story.stub(:validate_t).with(any_args).and_return(false)
+ @comic2 = Factory :comic, :author_id => @author.id
+ @storyc2 = Factory :story, :t => 0, :comic_id => @comic2.id, :panel_id => @panel.id, :author_id => @author.id
+ @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ @story4 = Factory :story, :t => 3, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ @story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ @ot = @story4.t
+ @story4.t = 1
+ end
+ it '既存のtに変化がない' do
+ @story4.store @ot
+ @story.reload
+ @story.t.should eq 0
+ @story2.reload
+ @story2.t.should eq 1
+ @story3.reload
+ @story3.t.should eq 2
+ @story4.reload
+ @story4.t.should eq 3
+ @story5.reload
+ @story5.t.should eq 4
+ @storyc2.reload
+ @storyc2.t.should eq 0
+ end
+ it 'falseを返す' do
+ r = @story4.store @ot
+ r.should be_false
+ end
+ it 'tにエラーメッセージが入っている' do
+ @story4.store @ot
+ @story4.errors[:t].should_not be_empty
+ @story4.valid?.should be_true
+ end
+ end
+ context '編集不可だったとき' do
+ before do
+ @story = Factory.build :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ Story.any_instance.stub(:allow?).and_return(false)
+ end
+ it '403Forbidden例外を返す' do
+ lambda{
+ @story.store
+ }.should raise_error(ActiveRecord::Forbidden)
+ end
+ end
+ end
+ describe '切り詰め処理つき削除に於いて' do
+ before do
+ @comic = Factory :comic, :author_id => @author.id
+ @panel = Factory :panel, :author_id => @author.id
+ @story = Factory :story, :t => 0, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ end
+ context 'つつがなく終わるとき' do
+ it '削除される' do
+ lambda{
+ @story.destroy_and_shorten
+ }.should change(Story, :count ).by(-1)
+ end
+ end
+ #連携テスト。切り詰めが直接DBをいじる
+ context '2件で先頭を削除したとき' do
+ before do
+ @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ end
+ it '行が削除される' do
+ lambda{
+ @story.destroy_and_shorten
+ }.should change(Story, :count ).by(-1)
+ end
+ it '先頭は削除される' do
+ @story.destroy_and_shorten
+ lambda{
+ Story.find @story.id
+ }.should raise_error(ActiveRecord::RecordNotFound)
+ end
+ it '2件目は前に詰められる' do
+ @story.destroy_and_shorten
+ @story2.reload
+ @story2.t.should eq 0
+ end
+ end
+ context '3件で先頭を削除したとき' do
+ before do
+ @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ end
+ it '行が削除される' do
+ lambda{
+ @story.destroy_and_shorten
+ }.should change(Story, :count ).by(-1)
+ end
+ it '先頭は削除される' do
+ @story.destroy_and_shorten
+ lambda{
+ Story.find @story.id
+ }.should raise_error(ActiveRecord::RecordNotFound)
+ end
+ it '2件目は前に詰められる' do
+ @story.destroy_and_shorten
+ @story2.reload
+ @story2.t.should eq 0
+ end
+ it '3件目は前に詰められる' do
+ @story.destroy_and_shorten
+ @story3.reload
+ @story3.t.should eq 1
+ end
+ end
+ context '5件で3件目を削除したとき' do
+ before do
+ @story2 = Factory :story, :t => 1, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ @story3 = Factory :story, :t => 2, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ @story4 = Factory :story, :t => 3, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ @story5 = Factory :story, :t => 4, :comic_id => @comic.id, :panel_id => @panel.id, :author_id => @author.id
+ end
+ it '行が削除される' do
+ lambda{
+ @story3.destroy_and_shorten
+ }.should change(Story, :count ).by(-1)
+ end
+ it '1件目は変化がない' do
+ @story3.destroy_and_shorten
+ @story.reload
+ @story.t.should eq 0
+ end
+ it '2件目は変化がない' do
+ @story3.destroy_and_shorten
+ @story2.reload
+ @story2.t.should eq 1
+ end
+ it '3件目は削除される' do
+ @story3.destroy_and_shorten
+ lambda{
+ Story.find @story3.id
+ }.should raise_error(ActiveRecord::RecordNotFound)
+ end
+ it '4件目は前に詰められる' do
+ @story3.destroy_and_shorten
+ @story4.reload
+ @story4.t.should eq 2
+ end
+ it '5件目は前に詰められる' do
+ @story3.destroy_and_shorten
+ @story5.reload
+ @story5.t.should eq 3
+ end
+ end
+ #ロールバックテスト。切り詰めが直接DBをいじるので、すべてのケースで確実にロールバックを確認する
end
end