Skip to content

Commit bf70f5c

Browse files
authored
Treat all test package imports as test imports (sorbet#9595)
* Add a test * Treat all test package imports as test imports * Update tests
1 parent 269ea8e commit bf70f5c

File tree

10 files changed

+99
-49
lines changed

10 files changed

+99
-49
lines changed

packager/ComputePackageSCCs.h

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -138,22 +138,26 @@ class ComputePackageSCCs {
138138
// we've visited all members of the SCC once, to ensure that their ids have all been populated.
139139
for (auto name : condensationNode.members) {
140140
for (auto &i : packageGraph.getImports(name)) {
141-
// We want to consider all imports from test code, but only normal imports for application code.
141+
// The mangled name won't exist if the import was to a package that doesn't exist.
142+
if (!i.mangledName.exists()) {
143+
continue;
144+
}
145+
146+
int impId = 0;
147+
142148
if constexpr (EdgeType == core::packages::ImportType::Normal) {
143149
if (i.type != core::packages::ImportType::Normal) {
144150
continue;
145151
}
152+
impId = packageGraph.getSCCId(i.mangledName);
153+
} else {
154+
// If we're processing imports from a test package, we can't tell if those imports are used only
155+
// at application time, or application and test time. Conservatively, we consider the import to
156+
// be to the test package, which transitively depends on the application code, ensuring the
157+
// correct ordering for test packages.
158+
impId = packageGraph.getTestSCCId(i.mangledName);
146159
}
147160

148-
// The mangled name won't exist if the import was to a package that doesn't exist.
149-
if (!i.mangledName.exists()) {
150-
continue;
151-
}
152-
153-
// All of the imports of every member of the SCC will have been processed in the recursive step, so
154-
// we can assume the scc id of the target exists. Additionally, all imports are to the original
155-
// application code, which is why we don't consider using the `testSccID` here.
156-
auto impId = packageGraph.getSCCId(i.mangledName);
157161
if (impId == sccId) {
158162
continue;
159163
}

packager/packager.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,6 +1210,12 @@ class PackageDBPackageGraph {
12101210
return packageDB.getPackageInfo(packageName).sccID().value();
12111211
}
12121212

1213+
int getTestSCCId(MangledName packageName) const {
1214+
ENFORCE(packageDB.getPackageInfo(packageName).exists());
1215+
ENFORCE(packageDB.getPackageInfo(packageName).testSccID().has_value());
1216+
return packageDB.getPackageInfo(packageName).testSccID().value();
1217+
}
1218+
12131219
void setTestSCCId(MangledName packageName, int sccID) {
12141220
auto *pkgInfoPtr = packageDB.getPackageInfoNonConst(packageName);
12151221
if (!pkgInfoPtr) {

test/cli/condensation-package-autocorrect-missing-import/test.out

Lines changed: 35 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -335,16 +335,16 @@ use_cycle_package/foo.rb:13: Unable to resolve constant `Test` https://srb.help/
335335
NN |module Net
336336
^^^^^^^^^^
337337

338-
use_cycle_package/foo.test.rb:4: `Test::Foo::Bar::CyclePackage::TestUtil` resolves but its package is not imported https://srb.help/3718
338+
use_cycle_package/foo.test.rb:4: Unable to resolve constant `Bar` https://srb.help/5002
339339
4 | Test::Foo::Bar::CyclePackage::TestUtil
340-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
341-
cycle_package/__package.rb:5: Exported from package here
342-
5 |class Foo::Bar::CyclePackage < PackageSpec
343-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
340+
^^^^^^^^^^^^^^
344341
Autocorrect: Done
345-
use_cycle_package/__package.rb:7: Inserted `test_import Foo::Bar::CyclePackage, only: "test_rb"`
346-
7 | strict_dependencies 'layered_dag'
347-
^
342+
use_cycle_package/foo.test.rb:4: Replaced with `Dir`
343+
4 | Test::Foo::Bar::CyclePackage::TestUtil
344+
^^^^^^^^^^^^^^
345+
https://github.com/sorbet/sorbet/tree/master/rbi/core/dir.rbi#LCENSORED: `Dir` defined here
346+
NN |class Dir < Object
347+
^^^^^^^^^^^^^^^^^^
348348
Errors: 4
349349
# frozen_string_literal: true
350350
# typed: strict
@@ -353,7 +353,6 @@ Errors: 4
353353
class Foo::MyPackage < PackageSpec
354354
layer 'lib'
355355
strict_dependencies 'layered_dag'
356-
test_import Foo::Bar::CyclePackage, only: "test_rb"
357356
test_import Foo::Bar::CyclePackageTest
358357
end
359358

@@ -399,16 +398,16 @@ use_app_cycle_package/foo.rb:13: Unable to resolve constant `Test` https://srb.h
399398
NN |module Net
400399
^^^^^^^^^^
401400

402-
use_app_cycle_package/foo.test.rb:4: `Test::Foo::Bar::AppCyclePackage::TestUtil` resolves but its package is not imported https://srb.help/3718
401+
use_app_cycle_package/foo.test.rb:4: Unable to resolve constant `Bar` https://srb.help/5002
403402
4 | Test::Foo::Bar::AppCyclePackage::TestUtil
404-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
405-
app_cycle_package/__package.rb:5: Exported from package here
406-
5 |class Foo::Bar::AppCyclePackage < PackageSpec
407-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
408-
Autocorrect: Done
409-
use_app_cycle_package/__package.rb:7: Inserted `test_import Foo::Bar::AppCyclePackage, only: "test_rb"`
410-
7 | strict_dependencies 'layered_dag'
411-
^
403+
^^^^^^^^^^^^^^
404+
Autocorrect: Done
405+
use_app_cycle_package/foo.test.rb:4: Replaced with `Dir`
406+
4 | Test::Foo::Bar::AppCyclePackage::TestUtil
407+
^^^^^^^^^^^^^^
408+
https://github.com/sorbet/sorbet/tree/master/rbi/core/dir.rbi#LCENSORED: `Dir` defined here
409+
NN |class Dir < Object
410+
^^^^^^^^^^^^^^^^^^
412411
Errors: 4
413412
# frozen_string_literal: true
414413
# typed: strict
@@ -417,7 +416,6 @@ Errors: 4
417416
class Foo::MyPackage < PackageSpec
418417
layer 'lib'
419418
strict_dependencies 'layered_dag'
420-
test_import Foo::Bar::AppCyclePackage, only: "test_rb"
421419
test_import Foo::Bar::AppCyclePackageTest
422420
end
423421

@@ -463,16 +461,16 @@ use_false_cycle_package/foo.rb:13: Unable to resolve constant `Test` https://srb
463461
NN |module Net
464462
^^^^^^^^^^
465463

466-
use_false_cycle_package/foo.test.rb:4: `Test::Foo::Bar::FalseCyclePackage::TestUtil` resolves but its package is not imported https://srb.help/3718
464+
use_false_cycle_package/foo.test.rb:4: Unable to resolve constant `Bar` https://srb.help/5002
467465
4 | Test::Foo::Bar::FalseCyclePackage::TestUtil
468-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
469-
false_cycle_package/__package.rb:5: Exported from package here
470-
5 |class Foo::Bar::FalseCyclePackage < PackageSpec
471-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
472-
Autocorrect: Done
473-
use_false_cycle_package/__package.rb:7: Inserted `test_import Foo::Bar::FalseCyclePackage, only: "test_rb"`
474-
7 | strict_dependencies 'layered_dag'
475-
^
466+
^^^^^^^^^^^^^^
467+
Autocorrect: Done
468+
use_false_cycle_package/foo.test.rb:4: Replaced with `Dir`
469+
4 | Test::Foo::Bar::FalseCyclePackage::TestUtil
470+
^^^^^^^^^^^^^^
471+
https://github.com/sorbet/sorbet/tree/master/rbi/core/dir.rbi#LCENSORED: `Dir` defined here
472+
NN |class Dir < Object
473+
^^^^^^^^^^^^^^^^^^
476474
Errors: 4
477475
# frozen_string_literal: true
478476
# typed: strict
@@ -481,7 +479,6 @@ Errors: 4
481479
class Foo::MyPackage < PackageSpec
482480
layer 'lib'
483481
strict_dependencies 'layered_dag'
484-
test_import Foo::Bar::FalseCyclePackage, only: "test_rb"
485482
test_import Foo::Bar::FalseCyclePackageTest
486483
end
487484

@@ -527,16 +524,16 @@ use_app_false_cycle_package/foo.rb:13: Unable to resolve constant `Test` https:/
527524
NN |module Net
528525
^^^^^^^^^^
529526

530-
use_app_false_cycle_package/foo.test.rb:4: `Test::Foo::Bar::AppFalseCyclePackage::TestUtil` resolves but its package is not imported https://srb.help/3718
527+
use_app_false_cycle_package/foo.test.rb:4: Unable to resolve constant `Bar` https://srb.help/5002
531528
4 | Test::Foo::Bar::AppFalseCyclePackage::TestUtil
532-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
533-
app_false_cycle_package/__package.rb:5: Exported from package here
534-
5 |class Foo::Bar::AppFalseCyclePackage < PackageSpec
535-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
536-
Autocorrect: Done
537-
use_app_false_cycle_package/__package.rb:7: Inserted `test_import Foo::Bar::AppFalseCyclePackage, only: "test_rb"`
538-
7 | strict_dependencies 'layered_dag'
539-
^
529+
^^^^^^^^^^^^^^
530+
Autocorrect: Done
531+
use_app_false_cycle_package/foo.test.rb:4: Replaced with `Dir`
532+
4 | Test::Foo::Bar::AppFalseCyclePackage::TestUtil
533+
^^^^^^^^^^^^^^
534+
https://github.com/sorbet/sorbet/tree/master/rbi/core/dir.rbi#LCENSORED: `Dir` defined here
535+
NN |class Dir < Object
536+
^^^^^^^^^^^^^^^^^^
540537
Errors: 4
541538
# frozen_string_literal: true
542539
# typed: strict
@@ -545,6 +542,5 @@ Errors: 4
545542
class Foo::MyPackage < PackageSpec
546543
layer 'lib'
547544
strict_dependencies 'layered_dag'
548-
test_import Foo::Bar::AppFalseCyclePackage, only: "test_rb"
549545
test_import Foo::Bar::AppFalseCyclePackageTest
550546
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# typed: strict
2+
3+
class A < PackageSpec
4+
test_import B
5+
end
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# typed: strict
2+
3+
module Test::A
4+
class Example < Test::B::Helper
5+
end
6+
end
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# typed: strict
2+
3+
class B < PackageSpec
4+
test_import C
5+
export Test::B::Helper
6+
end
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# typed: strict
2+
3+
module Test::B
4+
class Helper
5+
end
6+
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# typed: strict
2+
3+
class C < PackageSpec
4+
import B
5+
end
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
No errors! Great job.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/usr/bin/env bash
2+
3+
# This test exercises test helper dependencies in the condensation graph,
4+
# ensuring that we model those dependencies correctly. In the example, the test
5+
# package for A must be checked after the test package for B, with C existing to
6+
# push the B test package later in the condensation graph traversal. If the
7+
# test_import dependency isn't correctly modeled in the condensation graph, A's
8+
# test package might be checked before B's, at which point we'll see a
9+
# resolution error for the superclass in A's test.
10+
11+
cd test/cli/condensation-package-test-import || exit 1
12+
13+
../../../main/sorbet --silence-dev-message --stripe-packages \
14+
--experimental-package-directed \
15+
--max-threads=0 a b c 2>&1

0 commit comments

Comments
 (0)