@@ -649,37 +649,176 @@ test_that("define_to_metacore(quiet) deprecation message is output when supplied
649649 )
650650})
651651
652- test_that(" Informative error when where_sep_sheet=TRUE but WhereClause sheet missing" , {
653- # This should trigger the helpful error message about where_sep_sheet
654- expect_error(
655- spec_to_metacore(
656- " spec_no_val.xlsx" , # Use relative path like the existing test
657- where_sep_sheet = TRUE , # This is the default, but being explicit
658- verbose = " silent"
659- ),
660- regexp = " where.*where_sep_sheet" ,
661- ignore.case = TRUE
662- )
663-
664- # Verify the error message contains helpful context
665- err <- tryCatch(
652+ test_that(" spec_to_metacore warns when where_sep_sheet=TRUE but no WHERE IDs exist in the spec" , {
653+ # spec_no_val.xlsx has no WHERE clause references (all-NA where column)
654+ expect_warning(
666655 spec_to_metacore(
667656 " spec_no_val.xlsx" ,
668657 where_sep_sheet = TRUE ,
669- verbose = " silent "
658+ verbose = " warn "
670659 ),
671- error = function (e ) conditionMessage(e )
660+ regexp = " where column needed"
661+ )
662+ })
663+
664+ test_that(" spec_type_to_value_spec warns when where_sep_sheet=TRUE but all where values are NA" , {
665+ val_sheet <- tibble :: tibble(
666+ Dataset = " ADSL" ,
667+ Variable = " AGE" ,
668+ Origin = " Derived" ,
669+ Type = " Num" ,
670+ Predecessor = NA_character_
671+ )
672+ doc <- list (ValueSpec = val_sheet )
673+ cols <- c(
674+ dataset = " ^Dataset$" ,
675+ variable = " ^Variable$" ,
676+ origin = " ^Origin$" ,
677+ type = " ^Type$" ,
678+ predecessor = " ^Predecessor$"
679+ )
680+
681+ expect_warning(
682+ spec_type_to_value_spec(doc , cols = cols , where_sep_sheet = TRUE , var_sheet = NULL ),
683+ regexp = " where column needed"
672684 )
685+ })
673686
674- # Check that the error message mentions:
675- # 1. That columns couldn't be matched
676- expect_match(err , " Unable to identify a sheet|Could not find matching columns" , ignore.case = TRUE )
687+ test_that(" spec_type_to_value_spec replaces where IDs with text from the separate where sheet" , {
688+ val_sheet <- tibble :: tibble(
689+ Dataset = " ADSL" ,
690+ Variable = " AGE" ,
691+ Origin = " Derived" ,
692+ Type = " Num" ,
693+ Predecessor = NA_character_ ,
694+ Where = " W01"
695+ )
696+ where_sheet <- tibble :: tibble(
697+ ID = " W01" ,
698+ Variable = " AGEGR" ,
699+ Comparator = " GE" ,
700+ Value = " 18"
701+ )
702+ doc <- list (ValueSpec = val_sheet , WhereSheet = where_sheet )
703+ cols <- c(
704+ dataset = " ^Dataset$" ,
705+ variable = " ^Variable$" ,
706+ origin = " ^Origin$" ,
707+ type = " ^Type$" ,
708+ predecessor = " ^Predecessor$" ,
709+ where = " ^Where$"
710+ )
677711
678- # 2. Provides the helpful tip about where_sep_sheet
679- expect_match(err , " where_sep_sheet" , ignore.case = TRUE )
712+ result <- spec_type_to_value_spec(doc , cols = cols , where_sep_sheet = TRUE , var_sheet = NULL )
680713
681- # 3. Shows which sheet was closest
682- expect_match(err , " Sheet|Closest" , ignore.case = TRUE )
714+ expect_equal(result $ where , " AGEGR GE 18" )
715+ })
716+
717+ test_that(" spec_type_to_value_spec auto-generates derivation_id from origin when not in cols" , {
718+ val_sheet <- tibble :: tibble(
719+ Dataset = c(" ADSL" , " ADSL" ),
720+ Variable = c(" AGE" , " VISIT" ),
721+ Origin = c(" Assigned" , " Derived" ),
722+ Type = c(" Num" , " Char" ),
723+ Predecessor = c(NA_character_ , NA_character_ )
724+ )
725+ doc <- list (ValueSpec = val_sheet )
726+ # No derivation_id in cols — auto-generated at lines 786-795
727+ cols <- c(
728+ dataset = " ^Dataset$" ,
729+ variable = " ^Variable$" ,
730+ origin = " ^Origin$" ,
731+ type = " ^Type$" ,
732+ predecessor = " ^Predecessor$"
733+ )
734+
735+ result <- spec_type_to_value_spec(doc , cols = cols , where_sep_sheet = FALSE , var_sheet = NULL )
736+
737+ # origin "Assigned" → dataset.variable
738+ expect_equal(result $ derivation_id [result $ variable == " AGE" ], " ADSL.AGE" )
739+ # other origin → pred.dataset.variable
740+ expect_equal(result $ derivation_id [result $ variable == " VISIT" ], " pred.ADSL.VISIT" )
741+ })
742+
743+ test_that(" spec_type_to_var_spec errors when duplicate variables have different metadata without dataset col" , {
744+ vars_sheet <- tibble :: tibble(
745+ Variable = c(" VISIT" , " VISIT" ),
746+ Length = c(" 20" , " 40" ), # different lengths → same variable, different metadata
747+ Label = c(" Visit" , " Visit" ),
748+ Type = c(" Char" , " Char" ),
749+ Format = c(NA_character_ , NA_character_ )
750+ )
751+ doc <- list (Variables = vars_sheet )
752+ cols <- c(
753+ variable = " ^Variable$" ,
754+ length = " ^Length$" ,
755+ label = " ^Label$" ,
756+ type = " ^Type$" ,
757+ format = " ^Format$"
758+ )
759+
760+ expect_error(
761+ spec_type_to_var_spec(doc , cols = cols ),
762+ regexp = " repeated with different metadata"
763+ )
764+ expect_error(
765+ spec_type_to_var_spec(doc , cols = cols ),
766+ regexp = " VISIT"
767+ )
768+ })
769+
770+ test_that(" spec_type_to_var_spec passes when duplicate variables have identical metadata without dataset col" , {
771+ vars_sheet <- tibble :: tibble(
772+ Variable = c(" VISIT" , " VISIT" ),
773+ Length = c(" 20" , " 20" ), # identical rows — distinct() collapses to one
774+ Label = c(" Visit" , " Visit" ),
775+ Type = c(" Char" , " Char" ),
776+ Format = c(NA_character_ , NA_character_ )
777+ )
778+ doc <- list (Variables = vars_sheet )
779+ cols <- c(
780+ variable = " ^Variable$" ,
781+ length = " ^Length$" ,
782+ label = " ^Label$" ,
783+ type = " ^Type$" ,
784+ format = " ^Format$"
785+ )
786+
787+ result <- spec_type_to_var_spec(doc , cols = cols )
788+
789+ expect_equal(nrow(result ), 1L )
790+ expect_equal(result $ variable , " VISIT" )
791+ })
792+
793+ test_that(" build_from_sheet resolves ambiguous regex via exact anchoring" , {
794+ # "label" partially matches both "label" and "label_extra"; ^label$ matches only "label"
795+ sheet_data <- tibble :: tibble(label = 1 : 3 , label_extra = 4 : 6 , other = 7 : 9 )
796+ cols <- c(lbl = " label" , oth = " other" )
797+
798+ result <- metacore ::: build_from_sheet(sheet_data , cols , context = " test_table" , sheet_name = " TestSheet" )
799+
800+ expect_equal(result $ lbl , 1 : 3 )
801+ expect_equal(result $ oth , 7 : 9 )
802+ })
803+
804+ test_that(" build_from_sheet errors when exact anchoring still leaves ambiguity" , {
805+ # "label" matches "label_1" and "label_2"; ^label$ matches neither
806+ sheet_data <- tibble :: tibble(label_1 = 1 : 3 , label_2 = 4 : 6 )
807+ cols <- c(lbl = " label" )
808+
809+ expect_error(
810+ metacore ::: build_from_sheet(sheet_data , cols , context = " test_table" , sheet_name = " MySheet" ),
811+ regexp = " Unable to rename"
812+ )
813+ expect_error(
814+ metacore ::: build_from_sheet(sheet_data , cols , context = " test_table" , sheet_name = " MySheet" ),
815+ regexp = " Please check your regular expression for `test_table`"
816+ )
817+ # NULL context uses the generic hint
818+ expect_error(
819+ metacore ::: build_from_sheet(sheet_data , cols , context = NULL , sheet_name = " MySheet" ),
820+ regexp = " Please check your regular expressions"
821+ )
683822})
684823
685824test_that(" spec_to_metacore provides detailed information for failed regular expressions" , {
0 commit comments