Skip to content

printer: adds unit tests to reach 100% test coverage#745

Open
chris-ramon wants to merge 1 commit into
masterfrom
printer-tests
Open

printer: adds unit tests to reach 100% test coverage#745
chris-ramon wants to merge 1 commit into
masterfrom
printer-tests

Conversation

@chris-ramon

@chris-ramon chris-ramon commented Jun 7, 2026

Copy link
Copy Markdown
Member

Details

  • printer: adds unit tests to reach 100% test coverage
100% across all functions in printer.go. 
Changes to printer.go:
1. getMapSliceValue (lines 42-47): Removed default case from the switch, added break after the switch — the function-level return []interface{}{} is now reachable when the value exists but isn't []interface{}.
2. OperationDefinition (line 191): Replaced fmt.Sprintf("%v", node.Name) with direct field access — the name == "" check on line 199 is now reachable for nil/unset names (this also fixes the query short-form bug for anonymous queries).

Test Plan

  • Unit tests.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed printing of anonymous GraphQL operations.
    • Improved traversal behavior for nested path values in complex structures.
  • Tests

    • Added comprehensive test suite for printer functionality, covering value resolution, description formatting, and AST node printing.

@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR fixes two bugs in the GraphQL AST printer and introduces a comprehensive internal test suite. The getMapSliceValue function now breaks on non-matching types instead of immediately returning an empty slice, allowing continued path traversal. The OperationDefinition printer now reads operation names safely without nil-formatting artifacts. Tests validate all internal helpers, panic recovery, and reducer behavior across GraphQL node types.

Changes

Printer Bug Fixes and Test Suite

Layer / File(s) Summary
Core traversal and name formatting fixes
language/printer/printer.go
getMapSliceValue changes switch behavior on non-slice/non-map types to break and continue traversal. OperationDefinition reads node.Name.Value only when non-nil to handle anonymous operations without nil formatting.
Map and slice traversal helper tests
language/printer/printer_internal_test.go
Tests for getMapValue and getMapSliceValue cover missing keys, non-slice/non-map fallback, multi-token traversal, and slice extraction behavior, directly validating the traversal logic fix.
Description and formatting utility tests
language/printer/printer_internal_test.go
Tests for getDescription (nil handling, multi-line output), toSliceString (nil, non-slice, mixed-element conversion), indent (newline indentation), and helper utilities (join, wrap, block).
Panic recovery and comprehensive reducer tests
language/printer/printer_internal_test.go
Panic recovery test ensures Print completes safely when reducers fail. Extensive printDocASTReducer tests cover all GraphQL AST node types from Name through DirectiveDefinition, validating action results and stringified output for operation names, directives, descriptions, field arguments, schema definitions, and value nodes.

🎯 3 (Moderate) | ⏱️ ~25 minutes

A rabbit hops through printer code,
Fixing traversal paths with cheer,
Tests now dance through every node—
Anonymous ops, safe and clear! 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding unit tests to achieve 100% coverage for the printer package.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch printer-tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@language/printer/printer_internal_test.go`:
- Around line 277-281: The test currently only checks action ==
visitor.ActionUpdate and then discards val, which lets regressions in
OperationDefinition formatting pass; update the assertions in the
OperationDefinition test cases (the blocks that check action and set val) to
assert on val's concrete value/shape instead of `_ = val` — e.g., verify the
returned string contains the expected operation name and formatting (for the
cases covering lines around the `if action != visitor.ActionUpdate {` check),
replacing the `_ = val` placeholders with assertions that validate val is a
non-empty string and matches the expected operation-name formatting for each
OperationDefinition test case.

In `@language/printer/printer.go`:
- Around line 42-47: The loop in getMapSliceValue prematurely exits when the
type-switch on v (switch v := v.(type)) hits a non-slice branch because of the
stray "break", preventing traversal of dotted keys like "a.b"; remove that break
(or replace it with no-op/continue) so the for-loop can continue and allow
map[string]interface{} traversal to proceed, keeping only the case []interface{}
returning the slice and otherwise falling through to the existing map-access
logic in getMapSliceValue.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0e6d4af3-b61f-4c23-9b30-ef060a6aec0e

📥 Commits

Reviewing files that changed from the base of the PR and between 2e39e53 and 3844c38.

📒 Files selected for processing (2)
  • language/printer/printer.go
  • language/printer/printer_internal_test.go

Comment on lines +277 to +281
if action != visitor.ActionUpdate {
t.Fatalf("expected ActionUpdate, got %v", action)
}
_ = val

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Assert reducer output for OperationDefinition cases.

Lines 280, 306, and 325 discard val, so these tests can still pass if operation-name formatting regresses. Since this PR fixes that behavior, these should assert returned string shape/content.

Suggested assertion pattern
 import (
 	"fmt"
+	"strings"
 	"testing"
@@
-	_ = val
+	got, ok := val.(string)
+	if !ok {
+		t.Fatalf("expected string output, got %T", val)
+	}
+	if strings.HasPrefix(got, "query ") || strings.Contains(got, "<nil>") {
+		t.Fatalf("unexpected anonymous query format: %q", got)
+	}
@@
-	_ = val2
+	got2, ok := val2.(string)
+	if !ok {
+		t.Fatalf("expected string output, got %T", val2)
+	}
+	if !strings.Contains(got2, "mutation myMutation") {
+		t.Fatalf("unexpected mutation format: %q", got2)
+	}
@@
-	_ = val3
+	got3, ok := val3.(string)
+	if !ok {
+		t.Fatalf("expected string output, got %T", val3)
+	}
+	if !strings.HasPrefix(got3, "subscription ") {
+		t.Fatalf("unexpected subscription format: %q", got3)
+	}

Also applies to: 303-307, 322-326

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@language/printer/printer_internal_test.go` around lines 277 - 281, The test
currently only checks action == visitor.ActionUpdate and then discards val,
which lets regressions in OperationDefinition formatting pass; update the
assertions in the OperationDefinition test cases (the blocks that check action
and set val) to assert on val's concrete value/shape instead of `_ = val` —
e.g., verify the returned string contains the expected operation name and
formatting (for the cases covering lines around the `if action !=
visitor.ActionUpdate {` check), replacing the `_ = val` placeholders with
assertions that validate val is a non-empty string and matches the expected
operation-name formatting for each OperationDefinition test case.

Comment on lines 42 to 47
switch v := v.(type) {
case []interface{}:
return v
default:
return []interface{}{}
}
break
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Restore nested map traversal in getMapSliceValue.

Line 46 breaks the loop for any non-slice token, so dotted keys (for example "a.b") cannot traverse nested maps at all. That makes this helper inconsistent with the other dotted-path helpers and can return incorrect empty results for valid nested map inputs.

Suggested fix
 func getMapSliceValue(m map[string]interface{}, key string) []interface{} {
 	tokens := strings.Split(key, ".")
 	valMap := m
 	for _, token := range tokens {
 		v, ok := valMap[token]
 		if !ok {
 			return []interface{}{}
 		}
 		switch v := v.(type) {
 		case []interface{}:
 			return v
+		case map[string]interface{}:
+			valMap = v
+			continue
+		default:
+			return []interface{}{}
 		}
-		break
 	}
 	return []interface{}{}
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
switch v := v.(type) {
case []interface{}:
return v
default:
return []interface{}{}
}
break
}
func getMapSliceValue(m map[string]interface{}, key string) []interface{} {
tokens := strings.Split(key, ".")
valMap := m
for _, token := range tokens {
v, ok := valMap[token]
if !ok {
return []interface{}{}
}
switch v := v.(type) {
case []interface{}:
return v
case map[string]interface{}:
valMap = v
continue
default:
return []interface{}{}
}
}
return []interface{}{}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@language/printer/printer.go` around lines 42 - 47, The loop in
getMapSliceValue prematurely exits when the type-switch on v (switch v :=
v.(type)) hits a non-slice branch because of the stray "break", preventing
traversal of dotted keys like "a.b"; remove that break (or replace it with
no-op/continue) so the for-loop can continue and allow map[string]interface{}
traversal to proceed, keeping only the case []interface{} returning the slice
and otherwise falling through to the existing map-access logic in
getMapSliceValue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant