@@ -357,3 +357,395 @@ func Hello(name string) string {
357
357
assert .NotEqual (t , input , pkg .Files [0 ].Body )
358
358
assert .Equal (t , expected , pkg .Files [0 ].Body )
359
359
}
360
+
361
+ func TestTypeCheckMemPackage_RealmImports (t * testing.T ) {
362
+ t .Parallel ()
363
+
364
+ type testCase struct {
365
+ name string
366
+ pkg * gnovm.MemPackage
367
+ getter MemPackageGetter
368
+ check func (* testing.T , error )
369
+ }
370
+
371
+ tests := []testCase {
372
+ {
373
+ name : "realm package with init-only imports" ,
374
+ pkg : & gnovm.MemPackage {
375
+ Name : "gns" ,
376
+ Path : "gno.land/r/demo/gns" ,
377
+ Files : []* gnovm.MemFile {
378
+ {
379
+ Name : "gns.gno" ,
380
+ Body : `
381
+ package gns
382
+ import (
383
+ "std"
384
+ "gno.land/r/demo/registry"
385
+ )
386
+
387
+ var (
388
+ adminAddr std.Address
389
+ )
390
+
391
+ func init() {
392
+ registry.Register("gns")
393
+ }
394
+
395
+ func GetAdmin() string {
396
+ return string(adminAddr)
397
+ }` ,
398
+ },
399
+ },
400
+ },
401
+ getter : mockPackageGetter {
402
+ & gnovm.MemPackage {
403
+ Name : "std" ,
404
+ Path : "std" ,
405
+ Files : []* gnovm.MemFile {
406
+ {
407
+ Name : "std.gno" ,
408
+ Body : `
409
+ package std
410
+ type Address string` ,
411
+ },
412
+ },
413
+ },
414
+ & gnovm.MemPackage {
415
+ Name : "registry" ,
416
+ Path : "gno.land/r/demo/registry" ,
417
+ Files : []* gnovm.MemFile {
418
+ {
419
+ Name : "registry.gno" ,
420
+ Body : `
421
+ package registry
422
+ func Register(name string) {}` ,
423
+ },
424
+ },
425
+ },
426
+ },
427
+ check : func (t * testing.T , err error ) {
428
+ t .Helper ()
429
+ require .NoError (t , err , "should not report unused imports in realm packages" )
430
+ },
431
+ },
432
+ {
433
+ name : "realm package with cross-realm imports" ,
434
+ pkg : & gnovm.MemPackage {
435
+ Name : "gns" ,
436
+ Path : "gno.land/r/demo/gns" ,
437
+ Files : []* gnovm.MemFile {
438
+ {
439
+ Name : "gns.gno" ,
440
+ Body : `
441
+ package gns
442
+ import (
443
+ "gno.land/r/demo/token"
444
+ "gno.land/r/demo/registry"
445
+ )
446
+
447
+ func init() {
448
+ registry.Register()
449
+ }
450
+
451
+ func Transfer(t token.Token) {
452
+ t.Transfer()
453
+ }` ,
454
+ },
455
+ },
456
+ },
457
+ getter : mockPackageGetter {
458
+ & gnovm.MemPackage {
459
+ Name : "token" ,
460
+ Path : "gno.land/r/demo/token" ,
461
+ Files : []* gnovm.MemFile {
462
+ {
463
+ Name : "token.gno" ,
464
+ Body : `
465
+ package token
466
+ type Token interface {
467
+ Transfer()
468
+ }` ,
469
+ },
470
+ },
471
+ },
472
+ & gnovm.MemPackage {
473
+ Name : "registry" ,
474
+ Path : "gno.land/r/demo/registry" ,
475
+ Files : []* gnovm.MemFile {
476
+ {
477
+ Name : "registry.gno" ,
478
+ Body : `
479
+ package registry
480
+ func Register() {}` ,
481
+ },
482
+ },
483
+ },
484
+ },
485
+ check : func (t * testing.T , err error ) {
486
+ t .Helper ()
487
+ require .NoError (t , err , "should handle cross-realm imports correctly" )
488
+ },
489
+ },
490
+ {
491
+ name : "debug realm package import scope" ,
492
+ pkg : & gnovm.MemPackage {
493
+ Name : "gns" ,
494
+ Path : "gno.land/r/demo/gns" ,
495
+ Files : []* gnovm.MemFile {
496
+ {
497
+ Name : "gns.gno" ,
498
+ Body : `
499
+ package gns
500
+ import "gno.land/r/demo/registry"
501
+
502
+ func init() {
503
+ registry.Register("test")
504
+ }` ,
505
+ },
506
+ },
507
+ },
508
+ getter : & debugPackageGetter {
509
+ mockPackageGetter : mockPackageGetter {
510
+ & gnovm.MemPackage {
511
+ Name : "registry" ,
512
+ Path : "gno.land/r/demo/registry" ,
513
+ Files : []* gnovm.MemFile {
514
+ {
515
+ Name : "registry.gno" ,
516
+ Body : `
517
+ package registry
518
+ func Register(name string) {}` ,
519
+ },
520
+ },
521
+ },
522
+ },
523
+ },
524
+ check : func (t * testing.T , err error ) {
525
+ t .Helper ()
526
+ require .NoError (t , err )
527
+ },
528
+ },
529
+ }
530
+
531
+ for _ , tc := range tests {
532
+ tc := tc
533
+ t .Run (tc .name , func (t * testing.T ) {
534
+ t .Parallel ()
535
+ err := TypeCheckMemPackage (tc .pkg , tc .getter , false )
536
+ if tc .check != nil {
537
+ tc .check (t , err )
538
+ } else {
539
+ require .NoError (t , err )
540
+ }
541
+ })
542
+ }
543
+ }
544
+
545
+ func TestTypeCheckMemPackage_InitAndCallbacks (t * testing.T ) {
546
+ t .Parallel ()
547
+
548
+ type testCase struct {
549
+ name string
550
+ pkg * gnovm.MemPackage
551
+ getter MemPackageGetter
552
+ check func (* testing.T , error )
553
+ }
554
+
555
+ tests := []testCase {
556
+ {
557
+ name : "callback registration in init" ,
558
+ pkg : & gnovm.MemPackage {
559
+ Name : "callback" ,
560
+ Path : "gno.land/r/demo/callback" ,
561
+ Files : []* gnovm.MemFile {
562
+ {
563
+ Name : "callback.gno" ,
564
+ Body : `
565
+ package callback
566
+ import "gno.land/r/demo/events"
567
+
568
+ func MintCallback(amount uint64) {
569
+ // will be called at runtime
570
+ }
571
+
572
+ func init() {
573
+ events.RegisterCallback("mint", MintCallback)
574
+ }` ,
575
+ },
576
+ },
577
+ },
578
+ getter : mockPackageGetter {
579
+ & gnovm.MemPackage {
580
+ Name : "events" ,
581
+ Path : "gno.land/r/demo/events" ,
582
+ Files : []* gnovm.MemFile {
583
+ {
584
+ Name : "events.gno" ,
585
+ Body : `
586
+ package events
587
+
588
+ type CallbackFn func(uint64)
589
+
590
+ func RegisterCallback(event string, fn CallbackFn) {}` ,
591
+ },
592
+ },
593
+ },
594
+ },
595
+ check : func (t * testing.T , err error ) {
596
+ t .Helper ()
597
+ require .NoError (t , err , "callback registration should be recognized as package usage" )
598
+ },
599
+ },
600
+ {
601
+ name : "multiple aliases with init usage" ,
602
+ pkg : & gnovm.MemPackage {
603
+ Name : "main" ,
604
+ Path : "gno.land/r/demo/main" ,
605
+ Files : []* gnovm.MemFile {
606
+ {
607
+ Name : "main.gno" ,
608
+ Body : `
609
+ package main
610
+
611
+ import (
612
+ ev "gno.land/r/demo/events"
613
+ cb "gno.land/r/demo/callback"
614
+ )
615
+
616
+ func ProcessEvent(amount uint64) {
617
+ // will be called at runtime
618
+ }
619
+
620
+ func init() {
621
+ ev.RegisterCallback("process", ProcessEvent)
622
+ cb.SetHandler(ProcessEvent)
623
+ }` ,
624
+ },
625
+ },
626
+ },
627
+ getter : mockPackageGetter {
628
+ & gnovm.MemPackage {
629
+ Name : "events" ,
630
+ Path : "gno.land/r/demo/events" ,
631
+ Files : []* gnovm.MemFile {
632
+ {
633
+ Name : "events.gno" ,
634
+ Body : `
635
+ package events
636
+ type CallbackFn func(uint64)
637
+ func RegisterCallback(event string, fn CallbackFn) {}` ,
638
+ },
639
+ },
640
+ },
641
+ & gnovm.MemPackage {
642
+ Name : "callback" ,
643
+ Path : "gno.land/r/demo/callback" ,
644
+ Files : []* gnovm.MemFile {
645
+ {
646
+ Name : "callback.gno" ,
647
+ Body : `
648
+ package callback
649
+ type HandlerFn func(uint64)
650
+ func SetHandler(fn HandlerFn) {}` ,
651
+ },
652
+ },
653
+ },
654
+ },
655
+ check : func (t * testing.T , err error ) {
656
+ t .Helper ()
657
+ require .NoError (t , err , "aliased imports in init should be recognized" )
658
+ },
659
+ },
660
+ {
661
+ name : "init with deferred callback setup" ,
662
+ pkg : & gnovm.MemPackage {
663
+ Name : "deferred" ,
664
+ Path : "gno.land/r/demo/deferred" ,
665
+ Files : []* gnovm.MemFile {
666
+ {
667
+ Name : "deferred.gno" ,
668
+ Body : `
669
+ package deferred
670
+
671
+ import handler "gno.land/r/demo/handler"
672
+
673
+ var setupCallback func()
674
+
675
+ func init() {
676
+ setupCallback = func() {
677
+ handler.Register("deferred", processEvent)
678
+ }
679
+ setupCallback()
680
+ }
681
+
682
+ func processEvent() {}` ,
683
+ },
684
+ },
685
+ },
686
+ getter : mockPackageGetter {
687
+ & gnovm.MemPackage {
688
+ Name : "handler" ,
689
+ Path : "gno.land/r/demo/handler" ,
690
+ Files : []* gnovm.MemFile {
691
+ {
692
+ Name : "handler.gno" ,
693
+ Body : `
694
+ package handler
695
+ func Register(name string, fn func()) {}` ,
696
+ },
697
+ },
698
+ },
699
+ },
700
+ check : func (t * testing.T , err error ) {
701
+ t .Helper ()
702
+ require .NoError (t , err , "deferred callback setup should be recognized" )
703
+ },
704
+ },
705
+ }
706
+
707
+ for _ , tc := range tests {
708
+ tc := tc
709
+ t .Run (tc .name , func (t * testing.T ) {
710
+ t .Parallel ()
711
+
712
+ debugGetter := & debugPackageGetter {
713
+ mockPackageGetter : tc .getter .(mockPackageGetter ),
714
+ }
715
+
716
+ err := TypeCheckMemPackage (tc .pkg , debugGetter , false )
717
+
718
+ t .Logf ("Imported packages: %v" , debugGetter .GetImportedPackages ())
719
+
720
+ if tc .check != nil {
721
+ tc .check (t , err )
722
+ } else {
723
+ require .NoError (t , err )
724
+ }
725
+ })
726
+ }
727
+ }
728
+
729
+ type debugPackageGetter struct {
730
+ mockPackageGetter
731
+ importedPkgs map [string ]bool
732
+ }
733
+
734
+ func (d * debugPackageGetter ) GetMemPackage (path string ) * gnovm.MemPackage {
735
+ if d .importedPkgs == nil {
736
+ d .importedPkgs = make (map [string ]bool )
737
+ }
738
+ pkg := d .mockPackageGetter .GetMemPackage (path )
739
+ if pkg != nil {
740
+ d .importedPkgs [path ] = true
741
+ }
742
+ return pkg
743
+ }
744
+
745
+ func (d * debugPackageGetter ) GetImportedPackages () []string {
746
+ var pkgs []string
747
+ for pkg := range d .importedPkgs {
748
+ pkgs = append (pkgs , pkg )
749
+ }
750
+ return pkgs
751
+ }
0 commit comments