diff --git a/app/models/account.rb b/app/models/account.rb index b41fe3e..b826226 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -117,6 +117,8 @@ def accent_label_color end def accent_color_rgb + return nil unless accent_color.present? + rgb = accent_color.match(/^#(..)(..)(..)$/).captures.map(&:hex) "rgb(#{rgb.join(', ')})" end diff --git a/test/models/account_test.rb b/test/models/account_test.rb new file mode 100644 index 0000000..f12db30 --- /dev/null +++ b/test/models/account_test.rb @@ -0,0 +1,112 @@ +# frozen_string_literal: true + +require 'test_helper' + +class AccountTest < ActiveSupport::TestCase + test 'should accept valid hex color for accent_color' do + account = Account.new( + email: 'test@example.com', + password: 'password123', + name: 'Test User', + slug: 'test-user', + accent_color: '#ff0000' + ) + assert account.valid? + end + + test 'should reject accent_color with CSS injection attempt' do + account = Account.new( + email: 'test2@example.com', + password: 'password123', + name: 'Test User 2', + slug: 'test-user-2', + accent_color: 'red; } body { display:none } .x {' + ) + assert_not account.valid? + assert account.errors[:accent_color].present? + end + + test 'should reject accent_color with closing style tag' do + account = Account.new( + email: 'test3@example.com', + password: 'password123', + name: 'Test User 3', + slug: 'test-user-3', + accent_color: '' + ) + assert_not account.valid? + assert account.errors[:accent_color].present? + end + + test 'should reject invalid hex colors' do + invalid_colors = [ + 'red', # Named color + '#ff00', # Too short + '#ff00000', # Too long + '#gggggg', # Invalid hex characters + 'rgb(255,0,0)', # RGB format + '#ff00;', # Hex with semicolon + '000000', # Missing # + ] + + invalid_colors.each do |color| + account = Account.new( + email: "test-#{color.gsub(/[^a-z0-9]/, '')}@example.com", + password: 'password123', + name: 'Test User', + slug: "test-user-#{color.gsub(/[^a-z0-9]/, '')}", + accent_color: color + ) + assert_not account.valid?, "#{color} should be invalid" + assert account.errors[:accent_color].present?, "#{color} should have accent_color error" + end + end + + test 'should accept valid hex colors with lowercase' do + account = Account.new( + email: 'test4@example.com', + password: 'password123', + name: 'Test User 4', + slug: 'test-user-4', + accent_color: '#abc123' + ) + assert account.valid? + end + + test 'should accept valid hex colors with uppercase' do + account = Account.new( + email: 'test5@example.com', + password: 'password123', + name: 'Test User 5', + slug: 'test-user-5', + accent_color: '#ABC123' + ) + assert account.valid? + end + + test 'should allow nil accent_color and set random color on save' do + account = Account.new( + email: 'test6@example.com', + password: 'password123', + name: 'Test User 6', + slug: 'test-user-6', + accent_color: nil + ) + # The validation allows nil + assert account.valid? + # But the set_random_accent_color callback should set a color on save + # (We don't save here to avoid database interactions in this unit test) + end + + test 'accent_color_rgb returns nil when accent_color is nil' do + account = Account.new + account.accent_color = nil + assert_nil account.accent_color_rgb + end + + test 'accent_color_rgb converts valid hex to rgb' do + account = Account.new + account.accent_color = '#ff0000' + assert_equal 'rgb(255, 0, 0)', account.accent_color_rgb + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..b96d6d3 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +ENV['RAILS_ENV'] ||= 'test' +require_relative '../config/environment' +require 'rails/test_help' + +module ActiveSupport + class TestCase + # Run tests in parallel with specified workers + parallelize(workers: :number_of_processors) + + # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. + fixtures :all if defined?(fixtures) + + # Add more helper methods to be used by all tests here... + end +end