@@ -689,45 +689,183 @@ func TestWriteTaskFileContent(t *testing.T) {
689689 emitTaskFrontmatter : tt .emitTaskFrontmatter ,
690690 output : & output ,
691691 logOut : & logOut ,
692+ includes : make (selectorMap ),
692693 }
693694
694- err := cc .writeTaskFileContent ()
695+ // Parse task file first
696+ if err := cc .parseTaskFile (); err != nil {
697+ if ! tt .wantErr {
698+ t .Errorf ("parseTaskFile() unexpected error: %v" , err )
699+ }
700+ return
701+ }
702+
703+ // Then emit the content
704+ err := cc .emitTaskFileContent ()
695705
696706 if tt .wantErr {
697707 if err == nil {
698- t .Errorf ("writeTaskFileContent () expected error, got nil" )
708+ t .Errorf ("emitTaskFileContent () expected error, got nil" )
699709 }
700710 } else {
701711 if err != nil {
702- t .Errorf ("writeTaskFileContent () unexpected error: %v" , err )
712+ t .Errorf ("emitTaskFileContent () unexpected error: %v" , err )
703713 }
704714 }
705715
706716 outputStr := output .String ()
707717 if tt .expectInOutput != "" {
708718 if ! strings .Contains (outputStr , tt .expectInOutput ) {
709- t .Errorf ("writeTaskFileContent () output should contain %q, got:\n %s" , tt .expectInOutput , outputStr )
719+ t .Errorf ("emitTaskFileContent () output should contain %q, got:\n %s" , tt .expectInOutput , outputStr )
710720 }
711721 }
712722
713723 // Additional checks for frontmatter emission
714724 if tt .emitTaskFrontmatter {
715725 // Verify frontmatter delimiters are present
716726 if ! strings .Contains (outputStr , "---" ) {
717- t .Errorf ("writeTaskFileContent () with emitTaskFrontmatter=true should contain '---' delimiters, got:\n %s" , outputStr )
727+ t .Errorf ("emitTaskFileContent () with emitTaskFrontmatter=true should contain '---' delimiters, got:\n %s" , outputStr )
718728 }
719729 // Verify YAML frontmatter structure
720730 if ! strings .Contains (outputStr , "task_name:" ) {
721- t .Errorf ("writeTaskFileContent () with emitTaskFrontmatter=true should contain 'task_name:' field, got:\n %s" , outputStr )
731+ t .Errorf ("emitTaskFileContent () with emitTaskFrontmatter=true should contain 'task_name:' field, got:\n %s" , outputStr )
722732 }
723733 // Verify task content is still present
724734 if ! strings .Contains (outputStr , "# Task with Frontmatter" ) {
725- t .Errorf ("writeTaskFileContent () should contain task content, got:\n %s" , outputStr )
735+ t .Errorf ("emitTaskFileContent () should contain task content, got:\n %s" , outputStr )
726736 }
727737 }
728738
729739 if ! tt .wantErr && cc .totalTokens <= 0 {
730- t .Errorf ("writeTaskFileContent() expected tokens > 0, got %d" , cc .totalTokens )
740+ t .Errorf ("emitTaskFileContent() expected tokens > 0, got %d" , cc .totalTokens )
741+ }
742+ })
743+ }
744+ }
745+
746+ func TestParseTaskFile (t * testing.T ) {
747+ tests := []struct {
748+ name string
749+ taskFile string
750+ setupFiles func (t * testing.T , tmpDir string ) string // returns task file path
751+ initialIncludes selectorMap
752+ expectedIncludes selectorMap // expected includes after parsing
753+ wantErr bool
754+ errContains string
755+ }{
756+ {
757+ name : "task without selectors field" ,
758+ taskFile : "task.md" ,
759+ initialIncludes : make (selectorMap ),
760+ expectedIncludes : make (selectorMap ),
761+ setupFiles : func (t * testing.T , tmpDir string ) string {
762+ taskPath := filepath .Join (tmpDir , "task.md" )
763+ createMarkdownFile (t , taskPath ,
764+ "task_name: test" ,
765+ "# Simple Task" )
766+ return taskPath
767+ },
768+ wantErr : false ,
769+ },
770+ {
771+ name : "task with selectors field" ,
772+ taskFile : "task.md" ,
773+ initialIncludes : make (selectorMap ),
774+ expectedIncludes : selectorMap {
775+ "language" : "Go" ,
776+ "env" : "prod" ,
777+ },
778+ setupFiles : func (t * testing.T , tmpDir string ) string {
779+ taskPath := filepath .Join (tmpDir , "task.md" )
780+ createMarkdownFile (t , taskPath ,
781+ "task_name: test\n selectors:\n language: Go\n env: prod" ,
782+ "# Task with Selectors" )
783+ return taskPath
784+ },
785+ wantErr : false ,
786+ },
787+ {
788+ name : "task with selectors merges with existing includes" ,
789+ taskFile : "task.md" ,
790+ initialIncludes : selectorMap {"existing" : "value" },
791+ expectedIncludes : selectorMap {
792+ "existing" : "value" ,
793+ "language" : "Python" ,
794+ },
795+ setupFiles : func (t * testing.T , tmpDir string ) string {
796+ taskPath := filepath .Join (tmpDir , "task.md" )
797+ createMarkdownFile (t , taskPath ,
798+ "task_name: test\n selectors:\n language: Python" ,
799+ "# Task with Selectors" )
800+ return taskPath
801+ },
802+ wantErr : false ,
803+ },
804+ {
805+ name : "task with invalid selectors field type" ,
806+ taskFile : "task.md" ,
807+ initialIncludes : make (selectorMap ),
808+ setupFiles : func (t * testing.T , tmpDir string ) string {
809+ taskPath := filepath .Join (tmpDir , "task.md" )
810+ createMarkdownFile (t , taskPath ,
811+ "task_name: test\n selectors: invalid" ,
812+ "# Task with Invalid Selectors" )
813+ return taskPath
814+ },
815+ wantErr : true ,
816+ errContains : "invalid 'selectors' field" ,
817+ },
818+ }
819+
820+ for _ , tt := range tests {
821+ t .Run (tt .name , func (t * testing.T ) {
822+ tmpDir := t .TempDir ()
823+ taskPath := tt .setupFiles (t , tmpDir )
824+
825+ cc := & codingContext {
826+ matchingTaskFile : taskPath ,
827+ includes : tt .initialIncludes ,
828+ }
829+ if cc .includes == nil {
830+ cc .includes = make (selectorMap )
831+ }
832+
833+ err := cc .parseTaskFile ()
834+
835+ if tt .wantErr {
836+ if err == nil {
837+ t .Errorf ("parseTaskFile() expected error, got nil" )
838+ } else if tt .errContains != "" && ! strings .Contains (err .Error (), tt .errContains ) {
839+ t .Errorf ("parseTaskFile() error = %v, should contain %q" , err , tt .errContains )
840+ }
841+ } else {
842+ if err != nil {
843+ t .Errorf ("parseTaskFile() unexpected error: %v" , err )
844+ }
845+
846+ // Verify selectors were extracted correctly
847+ for key , expectedValue := range tt .expectedIncludes {
848+ if actualValue , ok := cc .includes [key ]; ! ok {
849+ t .Errorf ("parseTaskFile() expected includes[%q] = %q, but key not found" , key , expectedValue )
850+ } else if actualValue != expectedValue {
851+ t .Errorf ("parseTaskFile() includes[%q] = %q, want %q" , key , actualValue , expectedValue )
852+ }
853+ }
854+
855+ // Verify all includes match expected (including initial includes)
856+ if len (cc .includes ) != len (tt .expectedIncludes ) {
857+ t .Errorf ("parseTaskFile() includes length = %d, want %d. Includes: %v" , len (cc .includes ), len (tt .expectedIncludes ), cc .includes )
858+ }
859+
860+ // Verify task content was stored
861+ if cc .taskContent == "" {
862+ t .Errorf ("parseTaskFile() expected taskContent to be set, got empty string" )
863+ }
864+
865+ // Verify task frontmatter was stored
866+ if cc .taskFrontmatter == nil {
867+ t .Errorf ("parseTaskFile() expected taskFrontmatter to be set, got nil" )
868+ }
731869 }
732870 })
733871 }
@@ -979,4 +1117,4 @@ func (f *fileInfoMock) Size() int64 { return 0 }
9791117func (f * fileInfoMock ) Mode () os.FileMode { return 0o644 }
9801118func (f * fileInfoMock ) ModTime () time.Time { return time.Time {} }
9811119func (f * fileInfoMock ) IsDir () bool { return f .isDir }
982- func (f * fileInfoMock ) Sys () interface {} { return nil }
1120+ func (f * fileInfoMock ) Sys () any { return nil }
0 commit comments