Skip to content

Commit 20d68a4

Browse files
committed
Add tests for UUID keys, polymorphic associations, and key registry
1 parent 0d9af29 commit 20d68a4

5 files changed

Lines changed: 413 additions & 1 deletion

File tree

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe "Association resolve" do
4+
let(:keys) do
5+
# Simple stub that generates keys on the fly
6+
Object.new.tap do |obj|
7+
def obj.resolve(table_name, record_name)
8+
FixtureBot::Key::Integer.generate(table_name, record_name)
9+
end
10+
end
11+
end
12+
13+
describe FixtureBot::Schema::BelongsTo do
14+
subject(:assoc) do
15+
FixtureBot::Schema::BelongsTo.new(name: :author, table: :users, foreign_key: :author_id)
16+
end
17+
18+
it "resolves to a hash with the foreign key column" do
19+
result = assoc.resolve(:admin, keys)
20+
expected_id = FixtureBot::Key::Integer.generate(:users, :admin)
21+
expect(result).to eq({ author_id: expected_id })
22+
end
23+
end
24+
25+
describe FixtureBot::Schema::PolymorphicBelongsTo do
26+
subject(:assoc) do
27+
FixtureBot::Schema::PolymorphicBelongsTo.new(
28+
name: :votable,
29+
foreign_key: :votable_id,
30+
foreign_type: :votable_type
31+
)
32+
end
33+
34+
it "resolves to a hash with both id and type columns" do
35+
table_ref = FixtureBot::Row::TableReference.new(table_name: :posts, record_name: :hello)
36+
result = assoc.resolve(table_ref, keys)
37+
expected_id = FixtureBot::Key::Integer.generate(:posts, :hello)
38+
expect(result).to eq({ votable_id: expected_id, votable_type: "Post" })
39+
end
40+
41+
it "classifies table names correctly" do
42+
table_ref = FixtureBot::Row::TableReference.new(table_name: :blog_posts, record_name: :hello)
43+
result = assoc.resolve(table_ref, keys)
44+
expect(result[:votable_type]).to eq("BlogPost")
45+
end
46+
end
47+
end

spec/fixturebot/features_spec.rb

Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe "New features" do
4+
describe "UUID tables" do
5+
let(:schema) do
6+
FixtureBot::Schema.define do
7+
table :projects, singular: :project, columns: [:name], key: FixtureBot::Key::Uuid
8+
end
9+
end
10+
11+
it "generates UUID primary keys" do
12+
result = FixtureBot.define(schema) do
13+
project :alpha do
14+
name "Alpha"
15+
end
16+
end
17+
18+
id = result.tables[:projects][:alpha][:id]
19+
expect(id).to match(/\A[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\z/)
20+
end
21+
22+
it "produces deterministic UUID keys" do
23+
result1 = FixtureBot.define(schema) do
24+
project :alpha do
25+
name "Alpha"
26+
end
27+
end
28+
result2 = FixtureBot.define(schema) do
29+
project :alpha do
30+
name "Alpha"
31+
end
32+
end
33+
expect(result1.tables[:projects][:alpha][:id]).to eq(result2.tables[:projects][:alpha][:id])
34+
end
35+
end
36+
37+
describe "belongs_to with UUID foreign keys" do
38+
let(:schema) do
39+
FixtureBot::Schema.define do
40+
table :projects, singular: :project, columns: [:name], key: FixtureBot::Key::Uuid
41+
table :tasks, singular: :task, columns: [:title, :project_id] do
42+
belongs_to :project, table: :projects
43+
end
44+
end
45+
end
46+
47+
it "resolves FK to UUID value" do
48+
result = FixtureBot.define(schema) do
49+
project :alpha do
50+
name "Alpha"
51+
end
52+
53+
task :first do
54+
title "First task"
55+
project :alpha
56+
end
57+
end
58+
59+
project_id = result.tables[:projects][:alpha][:id]
60+
task_project_id = result.tables[:tasks][:first][:project_id]
61+
expect(task_project_id).to eq(project_id)
62+
expect(task_project_id).to match(/\A[0-9a-f]{8}-/)
63+
end
64+
end
65+
66+
describe "polymorphic associations" do
67+
let(:schema) do
68+
FixtureBot::Schema.define do
69+
table :posts, singular: :post, columns: [:title]
70+
table :comments, singular: :comment, columns: [:body]
71+
table :votes, singular: :vote, columns: [:votable_id, :votable_type, :score] do
72+
polymorphic :votable
73+
end
74+
end
75+
end
76+
77+
it "sets both _id and _type columns" do
78+
result = FixtureBot.define(schema) do
79+
post :hello do
80+
title "Hello"
81+
end
82+
83+
vote :upvote do
84+
votable post(:hello)
85+
score 1
86+
end
87+
end
88+
89+
vote = result.tables[:votes][:upvote]
90+
post_id = result.tables[:posts][:hello][:id]
91+
expect(vote[:votable_id]).to eq(post_id)
92+
expect(vote[:votable_type]).to eq("Post")
93+
expect(vote[:score]).to eq(1)
94+
end
95+
96+
it "works with different target tables" do
97+
result = FixtureBot.define(schema) do
98+
post :hello do
99+
title "Hello"
100+
end
101+
comment :nice do
102+
body "Nice"
103+
end
104+
105+
vote :upvote_post do
106+
votable post(:hello)
107+
score 1
108+
end
109+
vote :upvote_comment do
110+
votable comment(:nice)
111+
score 1
112+
end
113+
end
114+
115+
expect(result.tables[:votes][:upvote_post][:votable_type]).to eq("Post")
116+
expect(result.tables[:votes][:upvote_comment][:votable_type]).to eq("Comment")
117+
expect(result.tables[:votes][:upvote_post][:votable_id]).to eq(result.tables[:posts][:hello][:id])
118+
expect(result.tables[:votes][:upvote_comment][:votable_id]).to eq(result.tables[:comments][:nice][:id])
119+
end
120+
end
121+
122+
describe "hardcoded IDs" do
123+
let(:schema) do
124+
FixtureBot::Schema.define do
125+
table :users, singular: :user, columns: [:name]
126+
table :posts, singular: :post, columns: [:title, :author_id] do
127+
belongs_to :author, table: :users
128+
end
129+
end
130+
end
131+
132+
it "uses the hardcoded ID in the record" do
133+
result = FixtureBot.define(schema) do
134+
user :admin do
135+
id 42
136+
name "Admin"
137+
end
138+
end
139+
140+
expect(result.tables[:users][:admin][:id]).to eq(42)
141+
end
142+
143+
it "FK references resolve to hardcoded value" do
144+
result = FixtureBot.define(schema) do
145+
user :admin do
146+
id 42
147+
name "Admin"
148+
end
149+
150+
post :hello do
151+
title "Hello"
152+
author :admin
153+
end
154+
end
155+
156+
expect(result.tables[:posts][:hello][:author_id]).to eq(42)
157+
end
158+
end
159+
160+
describe "custom primary key column" do
161+
let(:schema) do
162+
FixtureBot::Schema.define do
163+
table :users, singular: :user, columns: [:name], primary_key: :uid
164+
end
165+
end
166+
167+
it "uses the custom PK column name" do
168+
result = FixtureBot.define(schema) do
169+
user :admin do
170+
name "Admin"
171+
end
172+
end
173+
174+
user = result.tables[:users][:admin]
175+
expect(user).to have_key(:uid)
176+
expect(user).not_to have_key(:id)
177+
expect(user[:uid]).to be > 0
178+
end
179+
180+
it "allows hardcoding custom PK" do
181+
result = FixtureBot.define(schema) do
182+
user :admin do
183+
uid 99
184+
name "Admin"
185+
end
186+
end
187+
188+
expect(result.tables[:users][:admin][:uid]).to eq(99)
189+
end
190+
end
191+
192+
describe "custom key strategy" do
193+
it "accepts any object responding to #generate" do
194+
custom_strategy = Object.new
195+
def custom_strategy.generate(table_name, record_name)
196+
"#{table_name}-#{record_name}".hash.abs
197+
end
198+
199+
schema = FixtureBot::Schema.define do
200+
table :items, singular: :item, columns: [:name], key: custom_strategy
201+
end
202+
203+
result = FixtureBot.define(schema) do
204+
item :first do
205+
name "First"
206+
end
207+
end
208+
209+
expected = custom_strategy.generate(:items, :first)
210+
expect(result.tables[:items][:first][:id]).to eq(expected)
211+
end
212+
end
213+
214+
describe "mixed integer and UUID tables" do
215+
let(:schema) do
216+
FixtureBot::Schema.define do
217+
table :users, singular: :user, columns: [:name]
218+
table :api_keys, singular: :api_key, columns: [:token, :user_id], key: FixtureBot::Key::Uuid do
219+
belongs_to :user, table: :users
220+
end
221+
end
222+
end
223+
224+
it "integer table has integer PK, UUID table has UUID PK" do
225+
result = FixtureBot.define(schema) do
226+
user :admin do
227+
name "Admin"
228+
end
229+
230+
api_key :main do
231+
token "abc123"
232+
user :admin
233+
end
234+
end
235+
236+
user_id = result.tables[:users][:admin][:id]
237+
api_key_id = result.tables[:api_keys][:main][:id]
238+
239+
expect(user_id).to be_a(::Integer)
240+
expect(api_key_id).to be_a(String)
241+
expect(api_key_id).to match(/\A[0-9a-f]{8}-/)
242+
243+
# FK from UUID table to integer table should be integer
244+
expect(result.tables[:api_keys][:main][:user_id]).to eq(user_id)
245+
end
246+
end
247+
248+
describe "polymorphic? duck type" do
249+
it "BelongsTo is not polymorphic" do
250+
assoc = FixtureBot::Schema::BelongsTo.new(name: :author, table: :users, foreign_key: :author_id)
251+
expect(assoc.polymorphic?).to be false
252+
end
253+
254+
it "PolymorphicBelongsTo is polymorphic" do
255+
assoc = FixtureBot::Schema::PolymorphicBelongsTo.new(name: :votable, foreign_key: :votable_id, foreign_type: :votable_type)
256+
expect(assoc.polymorphic?).to be true
257+
end
258+
259+
it "Table filters by polymorphic?" do
260+
schema = FixtureBot::Schema.define do
261+
table :posts, singular: :post, columns: [:title]
262+
table :votes, singular: :vote, columns: [:votable_id, :votable_type, :voter_id] do
263+
polymorphic :votable
264+
belongs_to :voter, table: :posts
265+
end
266+
end
267+
268+
table = schema.tables[:votes]
269+
expect(table.belongs_to_associations.map(&:name)).to eq([:voter])
270+
expect(table.polymorphic_associations.map(&:name)).to eq([:votable])
271+
end
272+
end
273+
end

spec/fixturebot/key_spec.rb

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe FixtureBot::Key do
4+
describe "Key::Integer" do
5+
subject(:strategy) { FixtureBot::Key::Integer }
6+
7+
it "generates deterministic IDs" do
8+
id1 = strategy.generate(:users, :admin)
9+
id2 = strategy.generate(:users, :admin)
10+
expect(id1).to eq(id2)
11+
end
12+
13+
it "generates positive integers" do
14+
id = strategy.generate(:users, :admin)
15+
expect(id).to be_a(::Integer)
16+
expect(id).to be > 0
17+
end
18+
19+
it "generates different IDs for different records" do
20+
id1 = strategy.generate(:users, :admin)
21+
id2 = strategy.generate(:users, :reader)
22+
expect(id1).not_to eq(id2)
23+
end
24+
end
25+
26+
describe "Key::Uuid" do
27+
subject(:strategy) { FixtureBot::Key::Uuid }
28+
29+
it "generates deterministic UUIDs" do
30+
id1 = strategy.generate(:users, :admin)
31+
id2 = strategy.generate(:users, :admin)
32+
expect(id1).to eq(id2)
33+
end
34+
35+
it "generates valid UUID format" do
36+
id = strategy.generate(:users, :admin)
37+
expect(id).to match(/\A[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\z/)
38+
end
39+
40+
it "generates different UUIDs for different records" do
41+
id1 = strategy.generate(:users, :admin)
42+
id2 = strategy.generate(:users, :reader)
43+
expect(id1).not_to eq(id2)
44+
end
45+
end
46+
47+
describe ".generate (backward compat)" do
48+
it "delegates to Integer strategy" do
49+
expect(FixtureBot::Key.generate(:users, :admin)).to eq(FixtureBot::Key::Integer.generate(:users, :admin))
50+
end
51+
end
52+
end

0 commit comments

Comments
 (0)