smartest 0.1.0.alpha1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,634 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
4
+
5
+ require "smartest/autorun"
6
+ require "fileutils"
7
+ require "stringio"
8
+ require "open3"
9
+ require "tmpdir"
10
+
11
+ module SmartestSelfTest
12
+ module_function
13
+
14
+ def test_case(name, block)
15
+ Smartest::TestCase.new(
16
+ name: name,
17
+ metadata: {},
18
+ block: block,
19
+ location: caller_locations(1, 1).first
20
+ )
21
+ end
22
+
23
+ def run_suite(suite)
24
+ output = StringIO.new
25
+ status = Smartest::Runner.new(suite: suite, reporter: Smartest::Reporter.new(output)).run
26
+
27
+ [status, output.string]
28
+ end
29
+
30
+ def capture_error(expected_error)
31
+ yield
32
+ rescue Exception => error
33
+ raise if Smartest.fatal_exception?(error)
34
+
35
+ unless error.is_a?(expected_error)
36
+ raise Smartest::AssertionFailed, "expected #{expected_error}, but raised #{error.class}: #{error.message}"
37
+ end
38
+
39
+ error
40
+ else
41
+ raise Smartest::AssertionFailed, "expected #{expected_error}, but nothing was raised"
42
+ end
43
+ end
44
+
45
+ class SelfTestRegisteredFixture < Smartest::Fixture
46
+ fixture :registered_user_name do
47
+ "Alice"
48
+ end
49
+ end
50
+
51
+ use_fixture SelfTestRegisteredFixture
52
+
53
+ test("registers fixture classes with use_fixture") do |registered_user_name:|
54
+ expect(registered_user_name).to eq("Alice")
55
+ end
56
+
57
+ test("runs a registered test") do
58
+ suite = Smartest::Suite.new
59
+ suite.tests.add(SmartestSelfTest.test_case("factorial", proc { expect(1 * 2 * 3).to eq(6) }))
60
+
61
+ status, output = SmartestSelfTest.run_suite(suite)
62
+
63
+ expect(status).to eq(0)
64
+ expect(output).to include("Running 1 test")
65
+ expect(output).to include("1 test, 1 passed, 0 failed")
66
+ end
67
+
68
+ test("reports expectation failures") do
69
+ suite = Smartest::Suite.new
70
+ suite.tests.add(SmartestSelfTest.test_case("bad math", proc { expect(1 + 1).to eq(3) }))
71
+
72
+ status, output = SmartestSelfTest.run_suite(suite)
73
+
74
+ expect(status).to eq(1)
75
+ expect(output).to include("expected 2 to eq 3")
76
+ expect(output).to include("1 test, 0 passed, 1 failed")
77
+ end
78
+
79
+ test("supports basic matchers") do
80
+ suite = Smartest::Suite.new
81
+ suite.tests.add(
82
+ SmartestSelfTest.test_case(
83
+ "matchers",
84
+ proc do
85
+ expect([1, 2, 3]).to include(2)
86
+ expect(nil).to be_nil
87
+ expect("value").not_to be_nil
88
+ expect { raise ArgumentError, "bad" }.to raise_error(ArgumentError)
89
+ end
90
+ )
91
+ )
92
+
93
+ status, = SmartestSelfTest.run_suite(suite)
94
+
95
+ expect(status).to eq(0)
96
+ end
97
+
98
+ test("resolves keyword fixture dependencies per test") do
99
+ calls = []
100
+
101
+ fixture_class = Class.new(Smartest::Fixture) do
102
+ fixture :user do
103
+ calls << :user
104
+ "Alice"
105
+ end
106
+
107
+ fixture :greeting do |user:|
108
+ "Hello, #{user}"
109
+ end
110
+ end
111
+
112
+ suite = Smartest::Suite.new
113
+ suite.fixture_classes.add(fixture_class)
114
+ suite.tests.add(SmartestSelfTest.test_case("first", proc { |greeting:| expect(greeting).to eq("Hello, Alice") }))
115
+ suite.tests.add(SmartestSelfTest.test_case("second", proc { |greeting:| expect(greeting).to eq("Hello, Alice") }))
116
+
117
+ status, = SmartestSelfTest.run_suite(suite)
118
+
119
+ expect(status).to eq(0)
120
+ expect(calls).to eq(%i[user user])
121
+ end
122
+
123
+ test("creates fresh fixture values and fixture instances for each test") do
124
+ markers = []
125
+ instances = []
126
+
127
+ fixture_class = Class.new(Smartest::Fixture) do
128
+ fixture :marker do
129
+ instances << self
130
+ Object.new
131
+ end
132
+ end
133
+
134
+ suite = Smartest::Suite.new
135
+ suite.fixture_classes.add(fixture_class)
136
+ suite.tests.add(SmartestSelfTest.test_case("first", proc { |marker:| markers << marker }))
137
+ suite.tests.add(SmartestSelfTest.test_case("second", proc { |marker:| markers << marker }))
138
+
139
+ status, = SmartestSelfTest.run_suite(suite)
140
+
141
+ expect(status).to eq(0)
142
+ expect(markers.length).to eq(2)
143
+ expect(markers[0].object_id).not_to eq(markers[1].object_id)
144
+ expect(instances.length).to eq(2)
145
+ expect(instances[0].object_id).not_to eq(instances[1].object_id)
146
+ end
147
+
148
+ test("caches fixture values within one test") do
149
+ calls = 0
150
+
151
+ fixture_class = Class.new(Smartest::Fixture) do
152
+ fixture :token do
153
+ calls += 1
154
+ Object.new
155
+ end
156
+
157
+ fixture :first do |token:|
158
+ token
159
+ end
160
+
161
+ fixture :second do |token:|
162
+ token
163
+ end
164
+ end
165
+
166
+ suite = Smartest::Suite.new
167
+ suite.fixture_classes.add(fixture_class)
168
+ suite.tests.add(SmartestSelfTest.test_case("same object", proc { |first:, second:| expect(first.object_id).to eq(second.object_id) }))
169
+
170
+ status, = SmartestSelfTest.run_suite(suite)
171
+
172
+ expect(status).to eq(0)
173
+ expect(calls).to eq(1)
174
+ end
175
+
176
+ test("suite fixtures are created once and cleaned up after the suite") do
177
+ events = []
178
+ servers = []
179
+
180
+ fixture_class = Class.new(Smartest::Fixture) do
181
+ suite_fixture :server do
182
+ events << :server_setup
183
+ server = Object.new
184
+ cleanup { events << :server_cleanup }
185
+ server
186
+ end
187
+ end
188
+
189
+ suite = Smartest::Suite.new
190
+ suite.fixture_classes.add(fixture_class)
191
+ suite.tests.add(SmartestSelfTest.test_case("first", proc { |server:| events << :first; servers << server }))
192
+ suite.tests.add(SmartestSelfTest.test_case("second", proc { |server:| events << :second; servers << server }))
193
+
194
+ status, = SmartestSelfTest.run_suite(suite)
195
+
196
+ expect(status).to eq(0)
197
+ expect(events).to eq(%i[server_setup first second server_cleanup])
198
+ expect(servers.length).to eq(2)
199
+ expect(servers[0].object_id).to eq(servers[1].object_id)
200
+ end
201
+
202
+ test("test fixtures can depend on suite fixtures") do
203
+ calls = []
204
+ server_ids = []
205
+ client_ids = []
206
+
207
+ fixture_class = Class.new(Smartest::Fixture) do
208
+ suite_fixture :server do
209
+ calls << :server
210
+ Object.new
211
+ end
212
+
213
+ fixture :client do |server:|
214
+ [server, Object.new]
215
+ end
216
+ end
217
+
218
+ suite = Smartest::Suite.new
219
+ suite.fixture_classes.add(fixture_class)
220
+ suite.tests.add(SmartestSelfTest.test_case("first", proc { |client:| server_ids << client.first.object_id; client_ids << client.last.object_id }))
221
+ suite.tests.add(SmartestSelfTest.test_case("second", proc { |client:| server_ids << client.first.object_id; client_ids << client.last.object_id }))
222
+
223
+ status, = SmartestSelfTest.run_suite(suite)
224
+
225
+ expect(status).to eq(0)
226
+ expect(calls).to eq([:server])
227
+ expect(server_ids.uniq.length).to eq(1)
228
+ expect(client_ids.uniq.length).to eq(2)
229
+ end
230
+
231
+ test("suite fixtures cannot depend on test fixtures") do
232
+ fixture_class = Class.new(Smartest::Fixture) do
233
+ fixture :user do
234
+ :user
235
+ end
236
+
237
+ suite_fixture :server do |user:|
238
+ user
239
+ end
240
+ end
241
+
242
+ suite = Smartest::Suite.new
243
+ suite.fixture_classes.add(fixture_class)
244
+ suite.tests.add(SmartestSelfTest.test_case("needs server", proc { |server:| expect(server).to eq(:server) }))
245
+
246
+ status, output = SmartestSelfTest.run_suite(suite)
247
+
248
+ expect(status).to eq(1)
249
+ expect(output).to include("suite-scoped fixture server cannot depend on test-scoped fixture user")
250
+ end
251
+
252
+ test("suite fixture setup failures are cached and cleaned up once") do
253
+ calls = 0
254
+ events = []
255
+
256
+ fixture_class = Class.new(Smartest::Fixture) do
257
+ suite_fixture :server do
258
+ calls += 1
259
+ cleanup { events << :server_cleanup }
260
+ raise "server setup failed"
261
+ end
262
+ end
263
+
264
+ suite = Smartest::Suite.new
265
+ suite.fixture_classes.add(fixture_class)
266
+ suite.tests.add(SmartestSelfTest.test_case("first", proc { |server:| expect(server).to eq(:server) }))
267
+ suite.tests.add(SmartestSelfTest.test_case("second", proc { |server:| expect(server).to eq(:server) }))
268
+
269
+ status, output = SmartestSelfTest.run_suite(suite)
270
+
271
+ expect(status).to eq(1)
272
+ expect(calls).to eq(1)
273
+ expect(events).to eq([:server_cleanup])
274
+ expect(output.scan("RuntimeError: server setup failed").length).to eq(2)
275
+ end
276
+
277
+ test("suite cleanup failures fail the run") do
278
+ fixture_class = Class.new(Smartest::Fixture) do
279
+ suite_fixture :browser do
280
+ cleanup { raise "browser close failed" }
281
+ :browser
282
+ end
283
+ end
284
+
285
+ suite = Smartest::Suite.new
286
+ suite.fixture_classes.add(fixture_class)
287
+ suite.tests.add(SmartestSelfTest.test_case("uses browser", proc { |browser:| expect(browser).to eq(:browser) }))
288
+
289
+ status, output = SmartestSelfTest.run_suite(suite)
290
+
291
+ expect(status).to eq(1)
292
+ expect(output).to include("Suite cleanup failures:")
293
+ expect(output).to include("cleanup failed: RuntimeError: browser close failed")
294
+ expect(output).to include("1 test, 1 passed, 0 failed, 1 suite cleanup failed")
295
+ end
296
+
297
+ test("runs cleanup in reverse order after failures") do
298
+ events = []
299
+
300
+ fixture_class = Class.new(Smartest::Fixture) do
301
+ fixture :server do
302
+ cleanup { events << :server }
303
+ :server
304
+ end
305
+
306
+ fixture :browser do |server:|
307
+ cleanup { events << :browser }
308
+ server
309
+ end
310
+ end
311
+
312
+ suite = Smartest::Suite.new
313
+ suite.fixture_classes.add(fixture_class)
314
+ suite.tests.add(SmartestSelfTest.test_case("fails", proc { |browser:| expect(browser).to eq(:nope) }))
315
+
316
+ status, = SmartestSelfTest.run_suite(suite)
317
+
318
+ expect(status).to eq(1)
319
+ expect(events).to eq(%i[browser server])
320
+ end
321
+
322
+ test("runs cleanup when fixture setup fails after cleanup registration") do
323
+ events = []
324
+
325
+ fixture_class = Class.new(Smartest::Fixture) do
326
+ fixture :server do
327
+ cleanup { events << :server }
328
+ raise "server setup failed"
329
+ end
330
+ end
331
+
332
+ suite = Smartest::Suite.new
333
+ suite.fixture_classes.add(fixture_class)
334
+ suite.tests.add(SmartestSelfTest.test_case("needs server", proc { |server:| expect(server).to eq(:server) }))
335
+
336
+ status, output = SmartestSelfTest.run_suite(suite)
337
+
338
+ expect(status).to eq(1)
339
+ expect(events).to eq([:server])
340
+ expect(output).to include("RuntimeError: server setup failed")
341
+ end
342
+
343
+ test("duplicate fixture names fail the test") do
344
+ first_fixture = Class.new(Smartest::Fixture) do
345
+ fixture(:user) { "Alice" }
346
+ end
347
+
348
+ second_fixture = Class.new(Smartest::Fixture) do
349
+ fixture(:user) { "Bob" }
350
+ end
351
+
352
+ suite = Smartest::Suite.new
353
+ suite.fixture_classes.add(first_fixture)
354
+ suite.fixture_classes.add(second_fixture)
355
+ suite.tests.add(SmartestSelfTest.test_case("needs user", proc { |user:| expect(user).to eq("Alice") }))
356
+
357
+ status, output = SmartestSelfTest.run_suite(suite)
358
+
359
+ expect(status).to eq(1)
360
+ expect(output).to include("duplicate fixture: user")
361
+ end
362
+
363
+ test("allows child fixture classes to override parent fixtures") do
364
+ parent_fixture = Class.new(Smartest::Fixture) do
365
+ fixture(:user_name) { "Parent" }
366
+ end
367
+
368
+ child_fixture = Class.new(parent_fixture) do
369
+ fixture(:user_name) { "Child" }
370
+ end
371
+
372
+ suite = Smartest::Suite.new
373
+ suite.fixture_classes.add(child_fixture)
374
+ suite.tests.add(SmartestSelfTest.test_case("uses override", proc { |user_name:| expect(user_name).to eq("Child") }))
375
+
376
+ status, = SmartestSelfTest.run_suite(suite)
377
+
378
+ expect(status).to eq(0)
379
+ end
380
+
381
+ test("circular fixture dependencies fail the test") do
382
+ fixture_class = Class.new(Smartest::Fixture) do
383
+ fixture(:a) { |b:| b }
384
+ fixture(:b) { |a:| a }
385
+ end
386
+
387
+ suite = Smartest::Suite.new
388
+ suite.fixture_classes.add(fixture_class)
389
+ suite.tests.add(SmartestSelfTest.test_case("cycle", proc { |a:| expect(a).to eq(:a) }))
390
+
391
+ status, output = SmartestSelfTest.run_suite(suite)
392
+
393
+ expect(status).to eq(1)
394
+ expect(output).to include("circular fixture dependency: a -> b -> a")
395
+ end
396
+
397
+ test("fixture blocks can call private helper methods") do
398
+ fixture_class = Class.new(Smartest::Fixture) do
399
+ fixture :user_name do
400
+ build_user_name("Alice")
401
+ end
402
+
403
+ private
404
+
405
+ def build_user_name(name)
406
+ name.upcase
407
+ end
408
+ end
409
+
410
+ suite = Smartest::Suite.new
411
+ suite.fixture_classes.add(fixture_class)
412
+ suite.tests.add(SmartestSelfTest.test_case("uses helper", proc { |user_name:| expect(user_name).to eq("ALICE") }))
413
+
414
+ status, = SmartestSelfTest.run_suite(suite)
415
+
416
+ expect(status).to eq(0)
417
+ end
418
+
419
+ test("rejects positional test parameters") do
420
+ error = SmartestSelfTest.capture_error(Smartest::InvalidFixtureParameterError) do
421
+ SmartestSelfTest.test_case("bad", proc { |_user| nil })
422
+ end
423
+
424
+ expect(error.message).to include("Positional fixture parameters are not supported.")
425
+ end
426
+
427
+ test("rejects positional fixture parameters") do
428
+ error = SmartestSelfTest.capture_error(Smartest::InvalidFixtureParameterError) do
429
+ Class.new(Smartest::Fixture) do
430
+ fixture(:bad) { |_server| nil }
431
+ end
432
+ end
433
+
434
+ expect(error.message).to include("Positional fixture dependencies are not supported.")
435
+ end
436
+
437
+ test("rejects invalid fixture scopes") do
438
+ error = SmartestSelfTest.capture_error(Smartest::InvalidFixtureScopeError) do
439
+ Class.new(Smartest::Fixture) do
440
+ fixture(:bad, scope: :file) { nil }
441
+ end
442
+ end
443
+
444
+ expect(error.message).to include("invalid fixture scope: :file")
445
+ expect(error.message).to include("supported scopes: test, suite")
446
+ end
447
+
448
+ test("cli loads files and returns failure status") do
449
+ Dir.mktmpdir do |dir|
450
+ smartest_dir = File.join(dir, "smartest")
451
+ FileUtils.mkdir_p(smartest_dir)
452
+ File.write(File.join(smartest_dir, "test_helper.rb"), <<~RUBY)
453
+ require "smartest/autorun"
454
+ RUBY
455
+
456
+ test_file = File.join(smartest_dir, "sample_test.rb")
457
+ File.write(test_file, <<~RUBY)
458
+ require "test_helper"
459
+
460
+ test("cli failure") do
461
+ expect("a").to eq("b")
462
+ end
463
+ RUBY
464
+
465
+ stdout, stderr, status = Open3.capture3(
466
+ { "RUBYLIB" => File.expand_path("../lib", __dir__) },
467
+ "ruby",
468
+ File.expand_path("../exe/smartest", __dir__),
469
+ "smartest/sample_test.rb",
470
+ chdir: dir
471
+ )
472
+
473
+ expect(status.success?).to eq(false)
474
+ expect(stderr).to eq("")
475
+ expect(stdout).to include("cli failure")
476
+ expect(stdout).to include("expected \"a\" to eq \"b\"")
477
+ end
478
+ end
479
+
480
+ test("cli default suite ignores minitest-style test directory") do
481
+ Dir.mktmpdir do |dir|
482
+ smartest_dir = File.join(dir, "smartest")
483
+ FileUtils.mkdir_p(smartest_dir)
484
+ File.write(File.join(smartest_dir, "test_helper.rb"), <<~RUBY)
485
+ require "smartest/autorun"
486
+ RUBY
487
+
488
+ File.write(File.join(smartest_dir, "sample_test.rb"), <<~RUBY)
489
+ require "test_helper"
490
+
491
+ test("smartest default") do
492
+ expect(1).to eq(1)
493
+ end
494
+ RUBY
495
+
496
+ minitest_dir = File.join(dir, "test")
497
+ FileUtils.mkdir_p(minitest_dir)
498
+ File.write(File.join(minitest_dir, "test_helper.rb"), <<~RUBY)
499
+ raise "loaded minitest helper"
500
+ RUBY
501
+ File.write(File.join(minitest_dir, "sample_test.rb"), <<~RUBY)
502
+ raise "loaded minitest test"
503
+ RUBY
504
+
505
+ stdout, stderr, status = Open3.capture3(
506
+ { "RUBYLIB" => File.expand_path("../lib", __dir__) },
507
+ "ruby",
508
+ File.expand_path("../exe/smartest", __dir__),
509
+ chdir: dir
510
+ )
511
+
512
+ expect(status.success?).to eq(true)
513
+ expect(stderr).to eq("")
514
+ expect(stdout).to include("smartest default")
515
+ expect(stdout).to include("1 test, 1 passed, 0 failed")
516
+ end
517
+ end
518
+
519
+ test("cli prints version") do
520
+ stdout, stderr, status = Open3.capture3(
521
+ { "RUBYLIB" => File.expand_path("../lib", __dir__) },
522
+ "ruby",
523
+ File.expand_path("../exe/smartest", __dir__),
524
+ "--version"
525
+ )
526
+
527
+ expect(status.success?).to eq(true)
528
+ expect(stderr).to eq("")
529
+ expect(stdout).to eq("#{Smartest::VERSION}\n")
530
+ end
531
+
532
+ test("cli prints help") do
533
+ stdout, stderr, status = Open3.capture3(
534
+ { "RUBYLIB" => File.expand_path("../lib", __dir__) },
535
+ "ruby",
536
+ File.expand_path("../exe/smartest", __dir__),
537
+ "--help"
538
+ )
539
+
540
+ expect(status.success?).to eq(true)
541
+ expect(stderr).to eq("")
542
+ expect(stdout).to include("Usage:")
543
+ expect(stdout).to include("smartest [paths...]")
544
+ expect(stdout).to include("smartest --init")
545
+ expect(stdout).to include("smartest/**/*_test.rb")
546
+ end
547
+
548
+ test("cli initializes a runnable test scaffold") do
549
+ Dir.mktmpdir do |dir|
550
+ stdout, stderr, status = Open3.capture3(
551
+ { "RUBYLIB" => File.expand_path("../lib", __dir__) },
552
+ "ruby",
553
+ File.expand_path("../exe/smartest", __dir__),
554
+ "--init",
555
+ chdir: dir
556
+ )
557
+
558
+ expect(status.success?).to eq(true)
559
+ expect(stderr).to eq("")
560
+ expect(stdout).to include("create smartest")
561
+ expect(stdout).to include("create smartest/fixtures")
562
+ expect(stdout).to include("create smartest/test_helper.rb")
563
+ expect(stdout).to include("create smartest/example_test.rb")
564
+ helper_contents = File.read(File.join(dir, "smartest/test_helper.rb"))
565
+ expect(helper_contents).to include('require "smartest/autorun"')
566
+ expect(helper_contents).to include('Dir[File.join(__dir__, "fixtures", "**", "*.rb")].sort.each')
567
+ expect(File.read(File.join(dir, "smartest/example_test.rb"))).to include('require "test_helper"')
568
+
569
+ nested_fixtures_dir = File.join(dir, "smartest/fixtures/nested")
570
+ FileUtils.mkdir_p(nested_fixtures_dir)
571
+ File.write(File.join(nested_fixtures_dir, "auto_loaded_fixture.rb"), <<~RUBY)
572
+ class AutoLoadedFixture < Smartest::Fixture
573
+ fixture :auto_loaded_message do
574
+ "loaded from smartest/fixtures"
575
+ end
576
+ end
577
+ RUBY
578
+
579
+ File.write(File.join(dir, "smartest/auto_loaded_fixture_test.rb"), <<~RUBY)
580
+ require "test_helper"
581
+
582
+ use_fixture AutoLoadedFixture
583
+
584
+ test("auto-loaded fixture") do |auto_loaded_message:|
585
+ expect(auto_loaded_message).to eq("loaded from smartest/fixtures")
586
+ end
587
+ RUBY
588
+
589
+ run_stdout, run_stderr, run_status = Open3.capture3(
590
+ { "RUBYLIB" => File.expand_path("../lib", __dir__) },
591
+ "ruby",
592
+ File.expand_path("../exe/smartest", __dir__),
593
+ chdir: dir
594
+ )
595
+
596
+ expect(run_status.success?).to eq(true)
597
+ expect(run_stderr).to eq("")
598
+ expect(run_stdout).to include("example")
599
+ expect(run_stdout).to include("auto-loaded fixture")
600
+ expect(run_stdout).to include("2 tests, 2 passed, 0 failed")
601
+ end
602
+ end
603
+
604
+ test("cli init does not overwrite existing scaffold files") do
605
+ Dir.mktmpdir do |dir|
606
+ smartest_dir = File.join(dir, "smartest")
607
+ fixture_dir = File.join(smartest_dir, "fixtures")
608
+ FileUtils.mkdir_p(fixture_dir)
609
+ helper_path = File.join(smartest_dir, "test_helper.rb")
610
+ example_path = File.join(smartest_dir, "example_test.rb")
611
+ fixture_path = File.join(fixture_dir, "custom_fixture.rb")
612
+ File.write(helper_path, "# custom helper\n")
613
+ File.write(example_path, "# custom test\n")
614
+ File.write(fixture_path, "# custom fixture\n")
615
+
616
+ stdout, stderr, status = Open3.capture3(
617
+ { "RUBYLIB" => File.expand_path("../lib", __dir__) },
618
+ "ruby",
619
+ File.expand_path("../exe/smartest", __dir__),
620
+ "--init",
621
+ chdir: dir
622
+ )
623
+
624
+ expect(status.success?).to eq(true)
625
+ expect(stderr).to eq("")
626
+ expect(stdout).to include("exist smartest")
627
+ expect(stdout).to include("exist smartest/fixtures")
628
+ expect(stdout).to include("exist smartest/test_helper.rb")
629
+ expect(stdout).to include("exist smartest/example_test.rb")
630
+ expect(File.read(helper_path)).to eq("# custom helper\n")
631
+ expect(File.read(example_path)).to eq("# custom test\n")
632
+ expect(File.read(fixture_path)).to eq("# custom fixture\n")
633
+ end
634
+ end
data/smartest.gemspec ADDED
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/smartest/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "smartest"
7
+ spec.version = Smartest::VERSION
8
+ spec.authors = ["Yusuke Iwaki"]
9
+
10
+ spec.summary = "A small Ruby test runner with keyword-first fixtures."
11
+ spec.description = "Smartest is a small Ruby test runner focused on readable top-level tests, explicit keyword-argument fixture dependencies, and optional fixture cleanup."
12
+ spec.homepage = "https://github.com/YusukeIwaki/smartest"
13
+ spec.license = "MIT"
14
+ spec.required_ruby_version = ">= 3.1"
15
+
16
+ spec.metadata = {
17
+ "allowed_push_host" => "https://rubygems.org",
18
+ "bug_tracker_uri" => "https://github.com/YusukeIwaki/smartest/issues",
19
+ "documentation_uri" => "https://smartest-rb.vercel.app/",
20
+ "homepage_uri" => spec.homepage,
21
+ "rubygems_mfa_required" => "true",
22
+ "source_code_uri" => "https://github.com/YusukeIwaki/smartest/tree/main"
23
+ }
24
+
25
+ spec.files = Dir.chdir(__dir__) do
26
+ Dir.glob(
27
+ [
28
+ "CHANGELOG.md",
29
+ "DEVELOPMENT.md",
30
+ "Gemfile",
31
+ "LICENSE",
32
+ "README.md",
33
+ "Rakefile",
34
+ "SMARTEST_DESIGN.md",
35
+ "exe/*",
36
+ "lib/**/*.rb",
37
+ "smartest.gemspec",
38
+ "smartest/**/*.rb"
39
+ ]
40
+ )
41
+ end
42
+
43
+ spec.bindir = "exe"
44
+ spec.executables = ["smartest"]
45
+ spec.require_paths = ["lib"]
46
+
47
+ spec.add_development_dependency "rake", "~> 13.0"
48
+ end