more tweaks
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
--require spec_helper
|
||||
--format documentation
|
||||
--color
|
||||
@@ -18,4 +18,7 @@ gem "sassc-rails"
|
||||
group :development, :test do
|
||||
gem "debug", platforms: %i[mri windows]
|
||||
gem "rubocop-rails-omakase", require: false
|
||||
gem "rspec-rails", "~> 7.0"
|
||||
gem "factory_bot_rails"
|
||||
gem "shoulda-matchers", "~> 6.0"
|
||||
end
|
||||
|
||||
@@ -11,7 +11,7 @@ class Api::DownloadsController < ApiController
|
||||
error code: 404, desc: "File not found"
|
||||
def show
|
||||
path = params[:path]
|
||||
return head :bad_request if path.blank?
|
||||
return render(json: { error: "Path is required" }, status: :bad_request) if path.blank?
|
||||
|
||||
full_path = DownloadService.new.call(
|
||||
path: path,
|
||||
@@ -23,7 +23,7 @@ class Api::DownloadsController < ApiController
|
||||
if full_path
|
||||
send_file full_path, disposition: "attachment", type: resolve_mime(full_path)
|
||||
else
|
||||
head :not_found
|
||||
render json: { error: "Not found" }, status: :not_found
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,7 +11,5 @@ class Api::ImagesController < ApiController
|
||||
def show
|
||||
image = ImageService.new.show(ImageShowInputDto.new(id: params[:id]))
|
||||
send_file image.file_path, type: image.content_type, disposition: "inline"
|
||||
rescue Errno::ENOENT
|
||||
head :not_found
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,6 +13,14 @@ class ApiController < ActionController::API
|
||||
render json: { error: "Not found" }, status: :not_found
|
||||
end
|
||||
|
||||
rescue_from Errno::ENOENT do |e|
|
||||
render json: { error: "Not found" }, status: :not_found
|
||||
end
|
||||
|
||||
rescue_from ArgumentError do |e|
|
||||
render json: { error: e.message }, status: :bad_request
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def resolve_mime(path)
|
||||
|
||||
@@ -6,14 +6,16 @@ module SoftwareUpdater
|
||||
metadata = parse_json_metadata(full_path("#{versioned}.metadata.json"))
|
||||
site_url = metadata.delete(:site)
|
||||
|
||||
software = update_or_create_software(metadata.merge(platform: "c64"))
|
||||
upsert_external_link(software.id, "Source Code", site_url) if site_url.present?
|
||||
ActiveRecord::Base.transaction do
|
||||
software = update_or_create_software(metadata.merge(platform: "c64"))
|
||||
upsert_external_link(software.id, "Source Code", site_url) if site_url.present?
|
||||
|
||||
create_release_if_not_exists(
|
||||
software_id: software.id,
|
||||
version: version,
|
||||
cartridge_path: full_path("#{versioned}.prg")
|
||||
)
|
||||
create_release_if_not_exists(
|
||||
software_id: software.id,
|
||||
version: version,
|
||||
cartridge_path: full_path("#{versioned}.prg")
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,14 +7,16 @@ module SoftwareUpdater
|
||||
metadata = parse_json_metadata(full_path("#{versioned}.metadata.json"))
|
||||
site_url = metadata.delete(:site)
|
||||
|
||||
software = update_or_create_software(metadata.merge(platform: "ebitengine"))
|
||||
upsert_external_link(software.id, "Source Code", site_url) if site_url.present?
|
||||
ActiveRecord::Base.transaction do
|
||||
software = update_or_create_software(metadata.merge(platform: "ebitengine"))
|
||||
upsert_external_link(software.id, "Source Code", site_url) if site_url.present?
|
||||
|
||||
create_release_if_not_exists(
|
||||
software_id: software.id,
|
||||
version: version,
|
||||
html_folder_path: full_path(versioned)
|
||||
)
|
||||
create_release_if_not_exists(
|
||||
software_id: software.id,
|
||||
version: version,
|
||||
html_folder_path: full_path(versioned)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,14 +7,16 @@ module SoftwareUpdater
|
||||
metadata = parse_json_metadata(full_path("#{versioned}.metadata.json"))
|
||||
site_url = metadata.delete(:site)
|
||||
|
||||
software = update_or_create_software(metadata.merge(platform: "love"))
|
||||
upsert_external_link(software.id, "Source Code", site_url) if site_url.present?
|
||||
ActiveRecord::Base.transaction do
|
||||
software = update_or_create_software(metadata.merge(platform: "love"))
|
||||
upsert_external_link(software.id, "Source Code", site_url) if site_url.present?
|
||||
|
||||
create_release_if_not_exists(
|
||||
software_id: software.id,
|
||||
version: version,
|
||||
html_folder_path: full_path(versioned)
|
||||
)
|
||||
create_release_if_not_exists(
|
||||
software_id: software.id,
|
||||
version: version,
|
||||
html_folder_path: full_path(versioned)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -10,17 +10,19 @@ module SoftwareUpdater
|
||||
metadata = parse_lua_metadata(full_path("#{versioned}.lua"))
|
||||
site_url = metadata.delete(:site)
|
||||
|
||||
software = update_or_create_software(metadata.merge(platform: "tic80"))
|
||||
upsert_external_link(software.id, "Source Code", site_url) if site_url.present?
|
||||
ActiveRecord::Base.transaction do
|
||||
software = update_or_create_software(metadata.merge(platform: "tic80"))
|
||||
upsert_external_link(software.id, "Source Code", site_url) if site_url.present?
|
||||
|
||||
create_release_if_not_exists(
|
||||
software_id: software.id,
|
||||
version: version,
|
||||
cartridge_path: full_path("#{versioned}.tic"),
|
||||
source_path: full_path("#{versioned}.lua"),
|
||||
html_folder_path: full_path(versioned),
|
||||
docs_folder_path: full_path(docs_dir)
|
||||
)
|
||||
create_release_if_not_exists(
|
||||
software_id: software.id,
|
||||
version: version,
|
||||
cartridge_path: full_path("#{versioned}.tic"),
|
||||
source_path: full_path("#{versioned}.lua"),
|
||||
html_folder_path: full_path(versioned),
|
||||
docs_folder_path: full_path(docs_dir)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
class DropArticlesTable < ActiveRecord::Migration[8.1]
|
||||
def up
|
||||
drop_table :articles
|
||||
end
|
||||
|
||||
def down
|
||||
create_table :articles, id: :integer, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci" do |t|
|
||||
t.text :content
|
||||
t.timestamp :created_at, default: -> { "CURRENT_TIMESTAMP" }
|
||||
t.string :slug
|
||||
t.string :title
|
||||
t.timestamp :updated_at, default: -> { "CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" }
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,21 @@
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Api::DownloadsController, type: :request do
|
||||
describe "GET /api/download" do
|
||||
it "returns bad_request without path" do
|
||||
get "/api/download"
|
||||
|
||||
expect(response).to have_http_status(:bad_request)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json["error"]).to eq("Path is required")
|
||||
end
|
||||
|
||||
it "returns not_found for invalid path" do
|
||||
get "/api/download", params: { path: "nonexistent/file.tic" }
|
||||
|
||||
expect(response).to have_http_status(:not_found)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json["error"]).to eq("Not found")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,18 @@
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Api::EventsController, type: :request do
|
||||
describe "GET /api/events" do
|
||||
it "returns upcoming events" do
|
||||
create(:event, name: "Future Jam", date: 1.week.from_now)
|
||||
create(:event, name: "Past Jam", date: 1.week.ago)
|
||||
|
||||
get "/api/events"
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
names = json.map { |e| e["name"] }
|
||||
expect(names).to include("Future Jam")
|
||||
expect(names).not_to include("Past Jam")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,25 @@
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Api::SoftwareController, type: :request do
|
||||
describe "GET /api/software" do
|
||||
it "returns all software with releases" do
|
||||
create(:software, name: "test-game", title: "Test Game")
|
||||
|
||||
get "/api/software"
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json["softwares"]).to be_an(Array)
|
||||
expect(json["softwares"].length).to eq(1)
|
||||
end
|
||||
|
||||
it "excludes soft-deleted software" do
|
||||
create(:software, deleted_at: Time.current)
|
||||
|
||||
get "/api/software"
|
||||
|
||||
json = JSON.parse(response.body)
|
||||
expect(json["softwares"]).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
FactoryBot.define do
|
||||
factory :download do
|
||||
file_path { "/test/file.tic" }
|
||||
ip_address { "127.0.0.1" }
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
FactoryBot.define do
|
||||
factory :event do
|
||||
name { "Test Event" }
|
||||
date { 1.week.from_now }
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
FactoryBot.define do
|
||||
factory :member do
|
||||
sequence(:nick) { |n| "member#{n}" }
|
||||
real_nick { "Real Name" }
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
FactoryBot.define do
|
||||
factory :release do
|
||||
software
|
||||
sequence(:version) { |n| "1.0.#{n}" }
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
FactoryBot.define do
|
||||
factory :software do
|
||||
sequence(:name) { |n| "game-#{n}" }
|
||||
title { "Test Game" }
|
||||
author { "dev" }
|
||||
platform { "tic80" }
|
||||
status { "development" }
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Download, type: :model do
|
||||
it { should validate_presence_of(:file_path) }
|
||||
it { should belong_to(:release).optional }
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Event, type: :model do
|
||||
it { should validate_presence_of(:name) }
|
||||
it { should validate_presence_of(:date) }
|
||||
|
||||
describe ".upcoming" do
|
||||
it "returns only future events" do
|
||||
future = create(:event, date: 1.week.from_now)
|
||||
create(:event, date: 1.week.ago)
|
||||
|
||||
expect(Event.upcoming).to eq([future])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,6 @@
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Member, type: :model do
|
||||
it { should validate_presence_of(:nick) }
|
||||
it { should validate_uniqueness_of(:nick) }
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Release, type: :model do
|
||||
it { should belong_to(:software) }
|
||||
it { should have_many(:downloads) }
|
||||
|
||||
describe "version uniqueness" do
|
||||
let(:software) { create(:software) }
|
||||
|
||||
it "prevents duplicate versions for same software" do
|
||||
create(:release, software: software, version: "1.0.0")
|
||||
dup = build(:release, software: software, version: "1.0.0")
|
||||
expect(dup).not_to be_valid
|
||||
end
|
||||
|
||||
it "allows same version across different software" do
|
||||
other_sw = create(:software)
|
||||
create(:release, software: software, version: "1.0.0")
|
||||
other = build(:release, software: other_sw, version: "1.0.0")
|
||||
expect(other).to be_valid
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,21 @@
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Software, type: :model do
|
||||
it { should validate_presence_of(:name) }
|
||||
it { should validate_presence_of(:title) }
|
||||
it { should validate_presence_of(:platform) }
|
||||
it { should validate_uniqueness_of(:name) }
|
||||
|
||||
it { should have_many(:releases).dependent(:destroy) }
|
||||
it { should have_many(:external_links).dependent(:destroy) }
|
||||
it { should have_many(:software_images).dependent(:destroy) }
|
||||
|
||||
describe "default scope" do
|
||||
it "excludes soft-deleted records" do
|
||||
active = create(:software)
|
||||
create(:software, deleted_at: Time.current)
|
||||
|
||||
expect(Software.all).to eq([active])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,28 @@
|
||||
require "spec_helper"
|
||||
ENV["RAILS_ENV"] ||= "test"
|
||||
require_relative "../config/environment"
|
||||
|
||||
abort("The Rails environment is running in production mode!") if Rails.env.production?
|
||||
require "rspec/rails"
|
||||
|
||||
begin
|
||||
ActiveRecord::Migration.maintain_test_schema!
|
||||
rescue ActiveRecord::PendingMigrationError => e
|
||||
abort e.to_s.strip
|
||||
end
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.fixture_paths = [ Rails.root.join("spec/fixtures") ]
|
||||
config.use_transactional_fixtures = true
|
||||
config.infer_spec_type_from_file_location!
|
||||
config.filter_rails_from_backtrace!
|
||||
|
||||
config.include FactoryBot::Syntax::Methods
|
||||
end
|
||||
|
||||
Shoulda::Matchers.configure do |config|
|
||||
config.integrate do |with|
|
||||
with.test_framework :rspec
|
||||
with.library :rails
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,20 @@
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe SoftwareHighlightedService do
|
||||
describe "#index" do
|
||||
it "returns nil when no highlighted software" do
|
||||
create(:software, highlighted: false)
|
||||
|
||||
result = described_class.new.index
|
||||
expect(result).to be_nil
|
||||
end
|
||||
|
||||
it "returns highlighted software" do
|
||||
sw = create(:software, highlighted: true, title: "Featured")
|
||||
|
||||
result = described_class.new.index
|
||||
expect(result).not_to be_nil
|
||||
expect(result[:software][:title]).to eq("Featured")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe UpdateService do
|
||||
describe "#update" do
|
||||
it "raises ArgumentError for unsupported platform" do
|
||||
input = UpdateInputDto.new(platform: "unknown", name: "game", version: "1.0")
|
||||
|
||||
expect { described_class.new.update(input) }.to raise_error(ArgumentError, /Unsupported platform/)
|
||||
end
|
||||
|
||||
it "routes to correct platform service" do
|
||||
input = UpdateInputDto.new(platform: "tic80", name: "game", version: "1.0")
|
||||
mock_service = instance_double(SoftwareUpdater::Tic80Service)
|
||||
|
||||
allow(SoftwareUpdater::Tic80Service).to receive(:new).and_return(mock_service)
|
||||
allow(mock_service).to receive(:update)
|
||||
|
||||
described_class.new.update(input)
|
||||
|
||||
expect(mock_service).to have_received(:update).with("game", "1.0")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,14 @@
|
||||
RSpec.configure do |config|
|
||||
config.expect_with :rspec do |expectations|
|
||||
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
||||
end
|
||||
|
||||
config.mock_with :rspec do |mocks|
|
||||
mocks.verify_partial_doubles = true
|
||||
end
|
||||
|
||||
config.shared_context_metadata_behavior = :apply_to_host_groups
|
||||
config.filter_run_when_matching :focus
|
||||
config.order = :random
|
||||
Kernel.srand config.seed
|
||||
end
|
||||
Reference in New Issue
Block a user