From 208db5d33c2c3073ed679ff8704d725bc684973b Mon Sep 17 00:00:00 2001
From: ptdewey <57921252+ptdewey@users.noreply.github.com>
Date: Wed, 19 Nov 2025 03:07:25 +0000
Subject: [PATCH] feat: add SnapJSON API and comprehensive JSON snapshot tests
Add new SnapJSON() public API function to snapshot JSON strings with
consistent formatting and validation. This includes:
- SnapJSON(t testingT, title string, jsonStr string) function that unmarshals
and formats JSON for deterministic snapshot comparison
- Enable utter.Config.SortKeys for consistent map key ordering in all snapshots
Add comprehensive test suite with 26 new snapshot tests:
- 12 complex Go structure tests (nested data, pointers, interfaces, edge cases)
- 14 SnapJSON-specific tests covering JSON marshaling, APIs, special characters
This ensures reliable snapshot testing for both Go structures and JSON data,
with all map keys sorted for deterministic output across test runs.
---
freeze.go | 19 +++++++++++++++++++
freeze_test.go | 367 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
__snapshots__/test_complex_j_s_o_n_structure.snap | 36 ++++++++++++++++++------------------
__snapshots__/test_complex_nested_structure.snap | 2 +-
__snapshots__/test_go_struct_marshalled_to_j_s_o_n.snap | 12 ++++++------
__snapshots__/test_j_s_o_n_array_of_objects.snap | 20 ++++++++++----------
__snapshots__/test_j_s_o_n_numbers.snap | 16 ++++++++--------
__snapshots__/test_j_s_o_n_object.snap | 22 +++++++++++-----------
__snapshots__/test_j_s_o_n_with_mixed_arrays.snap | 4 ++--
__snapshots__/test_j_s_o_n_with_special_characters.snap | 8 ++++----
__snapshots__/test_j_s_o_n_with_various_types.snap | 12 ++++++------
__snapshots__/test_large_j_s_o_n.snap | 28 ++++++++++++++--------------
__snapshots__/test_multiple_complex_structures.snap | 6 +++---
__snapshots__/test_nested_maps_and_slices.snap | 46 +++++++++++++++++++++++-----------------------
__snapshots__/test_snap_j_s_o_n_array_of_objects.snap | 30 ++++++++++++++++++++++++++++++
__snapshots__/test_snap_j_s_o_n_basic.snap | 13 +++++++++++++
__snapshots__/test_snap_j_s_o_n_compact_format.snap | 17 +++++++++++++++++
__snapshots__/test_snap_j_s_o_n_complex_a_p_i.snap | 43 +++++++++++++++++++++++++++++++++++++++++++
__snapshots__/test_snap_j_s_o_n_empty_structures.snap | 23 +++++++++++++++++++++++
__snapshots__/test_snap_j_s_o_n_large_nested_structure.snap | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
__snapshots__/test_snap_j_s_o_n_mixed_types.snap | 42 ++++++++++++++++++++++++++++++++++++++++++
__snapshots__/test_snap_j_s_o_n_real_world_example.snap | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
__snapshots__/test_snap_j_s_o_n_simple_array.snap | 13 +++++++++++++
__snapshots__/test_snap_j_s_o_n_with_nested_objects.snap | 27 +++++++++++++++++++++++++++
__snapshots__/test_snap_j_s_o_n_with_nulls.snap | 19 +++++++++++++++++++
__snapshots__/test_snap_j_s_o_n_with_numbers.snap | 35 +++++++++++++++++++++++++++++++++++
__snapshots__/test_snap_j_s_o_n_with_special_characters.snap | 16 ++++++++++++++++
__snapshots__/test_structure_with_empty_values.snap | 2 +-
__snapshots__/test_structure_with_interface.snap | 2 +-
29 file(s) changed, 962 insertion(s)(+), 108 deletion(s)(-)
diff --git a/freeze.go b/freeze.go
--- a/freeze.go
+++ b/freeze.go
@@ -1,6 +1,7 @@
package freeze
import (
+ "encoding/json"
"fmt"
"github.com/kortschak/utter"
@@ -15,10 +16,28 @@
// TODO: probably make this (and other things) configurable
func init() {
utter.Config.ElideType = true
+ utter.Config.SortKeys = true
}
func SnapString(t testingT, title string, content string) {
t.Helper()
+ snap(t, title, content)
+}
+
+// SnapJSON takes a JSON string, unmarshals it, and then marshals it back with
+// pretty-printing before snapshotting. This ensures consistent formatting and
+// validates the JSON structure.
+func SnapJSON(t testingT, title string, jsonStr string) {
+ t.Helper()
+
+ var data interface{}
+ if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
+ t.Error("failed to unmarshal JSON:", err)
+ return
+ }
+
+ // Format the JSON data using the same mechanism as Snap
+ content := formatValue(data)
snap(t, title, content)
}
diff --git a/freeze_test.go b/freeze_test.go
--- a/freeze_test.go
+++ b/freeze_test.go
@@ -942,6 +942,373 @@
}
// ============================================================================
+// SNAPJSON FUNCTION TESTS - Serialized JSON Strings
+// ============================================================================
+
+// TestSnapJSONBasic tests the SnapJSON function with basic JSON
+func TestSnapJSONBasic(t *testing.T) {
+ jsonStr := `{
+ "name": "John Doe",
+ "email": "john@example.com",
+ "age": 30,
+ "verified": true
+ }`
+
+ freeze.SnapJSON(t, "SnapJSON Basic Object", jsonStr)
+}
+
+// TestSnapJSONSimpleArray tests SnapJSON with simple arrays
+func TestSnapJSONSimpleArray(t *testing.T) {
+ jsonStr := `[
+ "apple",
+ "banana",
+ "orange",
+ "grape"
+ ]`
+
+ freeze.SnapJSON(t, "SnapJSON Simple Array", jsonStr)
+}
+
+// TestSnapJSONCompactFormat tests SnapJSON with compact (minified) JSON
+func TestSnapJSONCompactFormat(t *testing.T) {
+ jsonStr := `{"id":1,"name":"Product","price":99.99,"in_stock":true,"tags":["electronics","gadgets"]}`
+
+ freeze.SnapJSON(t, "SnapJSON Compact Format", jsonStr)
+}
+
+// TestSnapJSONWithNestedObjects tests SnapJSON with nested JSON structures
+func TestSnapJSONWithNestedObjects(t *testing.T) {
+ jsonStr := `{
+ "user": {
+ "id": 42,
+ "profile": {
+ "username": "jane_smith",
+ "avatar": "https://example.com/avatar.jpg",
+ "settings": {
+ "theme": "dark",
+ "notifications": true,
+ "language": "en"
+ }
+ },
+ "permissions": ["read", "write", "admin"]
+ },
+ "created_at": "2023-06-15T10:30:00Z"
+ }`
+
+ freeze.SnapJSON(t, "SnapJSON Nested Objects", jsonStr)
+}
+
+// TestSnapJSONComplexAPI tests SnapJSON with complex API response
+func TestSnapJSONComplexAPI(t *testing.T) {
+ jsonStr := `{
+ "status": "success",
+ "code": 200,
+ "data": {
+ "users": [
+ {
+ "id": 1,
+ "name": "Alice",
+ "role": "admin",
+ "department": "Engineering",
+ "active": true
+ },
+ {
+ "id": 2,
+ "name": "Bob",
+ "role": "user",
+ "department": "Sales",
+ "active": true
+ },
+ {
+ "id": 3,
+ "name": "Charlie",
+ "role": "user",
+ "department": "Marketing",
+ "active": false
+ }
+ ],
+ "pagination": {
+ "page": 1,
+ "per_page": 10,
+ "total": 3,
+ "total_pages": 1
+ }
+ },
+ "timestamp": "2023-11-18T21:45:30Z"
+ }`
+
+ freeze.SnapJSON(t, "SnapJSON Complex API Response", jsonStr)
+}
+
+// TestSnapJSONWithNulls tests SnapJSON handling of null values
+func TestSnapJSONWithNulls(t *testing.T) {
+ jsonStr := `{
+ "id": 1,
+ "name": "Item",
+ "description": null,
+ "category": null,
+ "tags": null,
+ "metadata": {
+ "created": "2023-01-01",
+ "updated": null,
+ "deleted": null
+ }
+ }`
+
+ freeze.SnapJSON(t, "SnapJSON With Nulls", jsonStr)
+}
+
+// TestSnapJSONArrayOfObjects tests SnapJSON with arrays of objects
+func TestSnapJSONArrayOfObjects(t *testing.T) {
+ jsonStr := `[
+ {
+ "id": 1,
+ "type": "post",
+ "title": "First Post",
+ "views": 150,
+ "likes": 42
+ },
+ {
+ "id": 2,
+ "type": "post",
+ "title": "Second Post",
+ "views": 280,
+ "likes": 75
+ },
+ {
+ "id": 3,
+ "type": "post",
+ "title": "Third Post",
+ "views": 450,
+ "likes": 120
+ }
+ ]`
+
+ freeze.SnapJSON(t, "SnapJSON Array of Objects", jsonStr)
+}
+
+// TestSnapJSONLargeNestedStructure tests SnapJSON with deeply nested JSON
+func TestSnapJSONLargeNestedStructure(t *testing.T) {
+ jsonStr := `{
+ "organization": {
+ "name": "TechCorp",
+ "id": "org_123",
+ "departments": [
+ {
+ "name": "Engineering",
+ "manager": "Alice",
+ "teams": [
+ {
+ "name": "Backend",
+ "lead": "John",
+ "members": [
+ {"id": 1, "name": "John", "level": "senior"},
+ {"id": 2, "name": "Jane", "level": "mid"}
+ ],
+ "projects": [
+ {"id": "proj_1", "name": "API Service", "status": "active"},
+ {"id": "proj_2", "name": "Database Optimization", "status": "planning"}
+ ]
+ },
+ {
+ "name": "Frontend",
+ "lead": "Bob",
+ "members": [
+ {"id": 3, "name": "Bob", "level": "senior"},
+ {"id": 4, "name": "Carol", "level": "junior"}
+ ],
+ "projects": [
+ {"id": "proj_3", "name": "Web App", "status": "active"}
+ ]
+ }
+ ]
+ },
+ {
+ "name": "Sales",
+ "manager": "Charlie",
+ "teams": [
+ {
+ "name": "Enterprise",
+ "lead": "Dave",
+ "members": [
+ {"id": 5, "name": "Dave", "level": "senior"},
+ {"id": 6, "name": "Eve", "level": "mid"}
+ ],
+ "projects": []
+ }
+ ]
+ }
+ ],
+ "metadata": {
+ "founded": "2020",
+ "employees": 150,
+ "locations": ["USA", "EU", "APAC"]
+ }
+ }
+ }`
+
+ freeze.SnapJSON(t, "SnapJSON Large Nested Structure", jsonStr)
+}
+
+// TestSnapJSONWithNumbers tests SnapJSON with various number formats
+func TestSnapJSONWithNumbers(t *testing.T) {
+ jsonStr := `{
+ "integers": [0, 1, -1, 42, -100, 9999999],
+ "floats": [0.0, 3.14, -2.5, 0.001, 1.23e-4, 5.67e10],
+ "financial": {
+ "revenue": 1000000.50,
+ "expenses": 750000.75,
+ "profit_margin": 0.2499
+ },
+ "measurements": {
+ "temperature": -40.5,
+ "distance": 1000.25,
+ "weight": 0.5
+ }
+ }`
+
+ freeze.SnapJSON(t, "SnapJSON With Numbers", jsonStr)
+}
+
+// TestSnapJSONWithSpecialCharacters tests SnapJSON with special chars
+func TestSnapJSONWithSpecialCharacters(t *testing.T) {
+ jsonStr := `{
+ "special": "!@#$%^&*()_+-=[]{}|;:',.<>?/",
+ "escaped": "line1\nline2\ttab\rcarriage",
+ "quotes": "He said \"hello\" and she said 'goodbye'",
+ "unicode": "Hello δΈη π Ω
Ψ±ΨΨ¨Ψ§ ΠΡΠΈΠ²Π΅Ρ",
+ "paths": "C:\\Users\\name\\Documents\\file.txt",
+ "html": "
Content
",
+ "regex": "^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$"
+ }`
+
+ freeze.SnapJSON(t, "SnapJSON With Special Characters", jsonStr)
+}
+
+// TestSnapJSONEmptyStructures tests SnapJSON with empty collections
+func TestSnapJSONEmptyStructures(t *testing.T) {
+ jsonStr := `{
+ "empty_array": [],
+ "empty_object": {},
+ "empty_string": "",
+ "zero": 0,
+ "false_value": false,
+ "null_value": null,
+ "nested": {
+ "empty": [],
+ "also_empty": {}
+ }
+ }`
+
+ freeze.SnapJSON(t, "SnapJSON Empty Structures", jsonStr)
+}
+
+// TestSnapJSONMixedTypes tests SnapJSON with mixed array types
+func TestSnapJSONMixedTypes(t *testing.T) {
+ jsonStr := `{
+ "mixed_array": [
+ "string",
+ 123,
+ 45.67,
+ true,
+ false,
+ null,
+ {"nested": "object"},
+ [1, 2, 3]
+ ],
+ "complex": [
+ {"type": "user", "id": 1},
+ {"type": "post", "id": 100},
+ [1, 2, 3],
+ "string",
+ null
+ ]
+ }`
+
+ freeze.SnapJSON(t, "SnapJSON Mixed Types", jsonStr)
+}
+
+// TestSnapJSONRealWorldExample tests SnapJSON with real-world API data
+func TestSnapJSONRealWorldExample(t *testing.T) {
+ jsonStr := `{
+ "success": true,
+ "data": {
+ "product": {
+ "id": "prod_12345",
+ "name": "Premium Wireless Headphones",
+ "sku": "PWH-001",
+ "description": "High-quality wireless headphones with noise cancellation",
+ "price": {
+ "amount": 199.99,
+ "currency": "USD",
+ "discount": 10,
+ "final_price": 179.99
+ },
+ "inventory": {
+ "total": 500,
+ "available": 425,
+ "reserved": 50,
+ "damaged": 25
+ },
+ "specifications": {
+ "battery_life": "30 hours",
+ "weight": "250g",
+ "colors": ["black", "white", "blue"],
+ "warranty_months": 24
+ },
+ "ratings": {
+ "average": 4.5,
+ "count": 1250,
+ "breakdown": {
+ "5": 750,
+ "4": 350,
+ "3": 100,
+ "2": 30,
+ "1": 20
+ }
+ },
+ "reviews": [
+ {
+ "id": "rev_001",
+ "user": "john_doe",
+ "rating": 5,
+ "title": "Excellent product!",
+ "content": "Great sound quality and comfortable to wear.",
+ "helpful": 25,
+ "created_at": "2023-11-15T10:30:00Z"
+ },
+ {
+ "id": "rev_002",
+ "user": "jane_smith",
+ "rating": 4,
+ "title": "Good but pricey",
+ "content": "Works well, could be cheaper.",
+ "helpful": 12,
+ "created_at": "2023-11-10T14:20:00Z"
+ }
+ ]
+ },
+ "related_products": [
+ {
+ "id": "prod_12346",
+ "name": "Headphone Case",
+ "price": 29.99
+ },
+ {
+ "id": "prod_12347",
+ "name": "Audio Cable",
+ "price": 14.99
+ }
+ ]
+ },
+ "request_id": "req_abc123def456",
+ "timestamp": "2023-11-18T22:00:00Z"
+ }`
+
+ freeze.SnapJSON(t, "SnapJSON Real World Example", jsonStr)
+}
+
+// ============================================================================
// HELPER FUNCTIONS
// ============================================================================
diff --git a/__snapshots__/test_complex_j_s_o_n_structure.snap b/__snapshots__/test_complex_j_s_o_n_structure.snap
--- a/__snapshots__/test_complex_j_s_o_n_structure.snap
+++ b/__snapshots__/test_complex_j_s_o_n_structure.snap
@@ -7,9 +7,11 @@
---
map[string]interface{}{
"api": map[string]interface{}{
- "version": "2.0",
"endpoints": []interface{}{
map[string]interface{}{
+ "auth_required": true,
+ "method": "GET",
+ "path": "/users",
"rate_limit": map[string]interface{}{
"requests": 100.0,
"window": "1m",
@@ -18,9 +20,7 @@
"200": map[string]interface{}{
"description": "Success",
"schema": map[string]interface{}{
- "type": "array",
"items": map[string]interface{}{
- "type": "object",
"properties": map[string]interface{}{
"id": map[string]interface{}{
"type": "integer",
@@ -29,49 +29,48 @@
"type": "string",
},
},
+ "type": "object",
},
+ "type": "array",
},
},
"401": map[string]interface{}{
"description": "Unauthorized",
},
},
- "path": "/users",
- "method": "GET",
- "auth_required": true,
},
map[string]interface{}{
"auth_required": true,
+ "method": "POST",
+ "path": "/users/{id}",
"rate_limit": map[string]interface{}{
"requests": 50.0,
"window": "1m",
},
- "path": "/users/{id}",
- "method": "POST",
},
},
"models": map[string]interface{}{
"User": map[string]interface{}{
"properties": map[string]interface{}{
"created_at": map[string]interface{}{
- "type": "string",
"format": "date-time",
+ "type": "string",
},
- "roles": map[string]interface{}{
- "type": "array",
- "items": map[string]interface{}{
- "type": "string",
- },
+ "email": map[string]interface{}{
+ "format": "email",
+ "type": "string",
},
"id": map[string]interface{}{
"type": "integer",
},
+ "roles": map[string]interface{}{
+ "items": map[string]interface{}{
+ "type": "string",
+ },
+ "type": "array",
+ },
"username": map[string]interface{}{
"type": "string",
- },
- "email": map[string]interface{}{
- "type": "string",
- "format": "email",
},
},
"required": []interface{}{
@@ -81,5 +80,6 @@
},
},
},
+ "version": "2.0",
},
}
diff --git a/__snapshots__/test_complex_nested_structure.snap b/__snapshots__/test_complex_nested_structure.snap
--- a/__snapshots__/test_complex_nested_structure.snap
+++ b/__snapshots__/test_complex_nested_structure.snap
@@ -26,12 +26,12 @@
},
Metadata: map[string]interface{}{
"language": "en",
+ "notifications": true,
"preferences": map[string]interface{}{
"email_frequency": "weekly",
"notifications": true,
},
"theme": "dark",
- "notifications": true,
},
},
Tags: []string{
diff --git a/__snapshots__/test_go_struct_marshalled_to_j_s_o_n.snap b/__snapshots__/test_go_struct_marshalled_to_j_s_o_n.snap
--- a/__snapshots__/test_go_struct_marshalled_to_j_s_o_n.snap
+++ b/__snapshots__/test_go_struct_marshalled_to_j_s_o_n.snap
@@ -6,19 +6,19 @@
version: 0.1.0
---
map[string]interface{}{
- "name": "Jane Smith",
- "email": "jane@example.com",
- "phone": "+1-555-0123",
+ "active": true,
"address": map[string]interface{}{
- "street": "456 Oak Ave",
"city": "San Francisco",
+ "street": "456 Oak Ave",
"zip": "94102",
},
+ "created_at": "2023-06-15T14:30:00Z",
+ "email": "jane@example.com",
+ "name": "Jane Smith",
+ "phone": "+1-555-0123",
"tags": []interface{}{
"vip",
"verified",
"premium",
},
- "active": true,
- "created_at": "2023-06-15T14:30:00Z",
}
diff --git a/__snapshots__/test_j_s_o_n_array_of_objects.snap b/__snapshots__/test_j_s_o_n_array_of_objects.snap
--- a/__snapshots__/test_j_s_o_n_array_of_objects.snap
+++ b/__snapshots__/test_j_s_o_n_array_of_objects.snap
@@ -7,29 +7,29 @@
---
[]interface{}{
map[string]interface{}{
- "type": "user",
- "id": 1.0,
"data": map[string]interface{}{
- "role": "admin",
"name": "Alice",
+ "role": "admin",
},
+ "id": 1.0,
+ "type": "user",
},
map[string]interface{}{
- "type": "post",
- "id": 100.0,
"data": map[string]interface{}{
+ "author_id": 1.0,
"likes": 42.0,
"title": "First Post",
- "author_id": 1.0,
},
+ "id": 100.0,
+ "type": "post",
},
map[string]interface{}{
- "type": "comment",
- "id": 500.0,
"data": map[string]interface{}{
- "post_id": 100.0,
- "content": "Great post!",
"author_id": 2.0,
+ "content": "Great post!",
+ "post_id": 100.0,
},
+ "id": 500.0,
+ "type": "comment",
},
}
diff --git a/__snapshots__/test_j_s_o_n_numbers.snap b/__snapshots__/test_j_s_o_n_numbers.snap
--- a/__snapshots__/test_j_s_o_n_numbers.snap
+++ b/__snapshots__/test_j_s_o_n_numbers.snap
@@ -6,20 +6,20 @@
version: 0.1.0
---
map[string]interface{}{
+ "edge_cases": map[string]interface{}{
+ "minus_one": -1.0,
+ "one": 1.0,
+ },
"floats": map[string]interface{}{
+ "negative_float": -42.5,
"pi": 3.14159265359,
"scientific": 0.000123,
- "negative_float": -42.5,
"small": 0.0001,
},
- "edge_cases": map[string]interface{}{
- "one": 1.0,
- "minus_one": -1.0,
- },
"integers": map[string]interface{}{
- "zero": 0.0,
- "positive": 42.0,
- "negative": -100.0,
"large": 9.999999999999e+12.0,
+ "negative": -100.0,
+ "positive": 42.0,
+ "zero": 0.0,
},
}
diff --git a/__snapshots__/test_j_s_o_n_object.snap b/__snapshots__/test_j_s_o_n_object.snap
--- a/__snapshots__/test_j_s_o_n_object.snap
+++ b/__snapshots__/test_j_s_o_n_object.snap
@@ -6,22 +6,22 @@
version: 0.1.0
---
map[string]interface{}{
+ "message": nil,
+ "status": "success",
"user": map[string]interface{}{
+ "created_at": "2023-01-15T10:30:00Z",
+ "email": "john@example.com",
+ "id": 1.0,
+ "profile": map[string]interface{}{
+ "bio": "Software engineer",
+ "first_name": "John",
+ "last_name": "Doe",
+ "verified": true,
+ },
"roles": []interface{}{
"user",
"admin",
},
- "created_at": "2023-01-15T10:30:00Z",
- "id": 1.0,
"username": "john_doe",
- "email": "john@example.com",
- "profile": map[string]interface{}{
- "first_name": "John",
- "last_name": "Doe",
- "bio": "Software engineer",
- "verified": true,
- },
},
- "status": "success",
- "message": nil,
}
diff --git a/__snapshots__/test_j_s_o_n_with_mixed_arrays.snap b/__snapshots__/test_j_s_o_n_with_mixed_arrays.snap
--- a/__snapshots__/test_j_s_o_n_with_mixed_arrays.snap
+++ b/__snapshots__/test_j_s_o_n_with_mixed_arrays.snap
@@ -44,12 +44,12 @@
"name": "Item 1",
},
map[string]interface{}{
- "name": "Item 2",
"id": 2.0,
+ "name": "Item 2",
},
map[string]interface{}{
- "name": "Item 3",
"id": 3.0,
+ "name": "Item 3",
},
},
}
diff --git a/__snapshots__/test_j_s_o_n_with_special_characters.snap b/__snapshots__/test_j_s_o_n_with_special_characters.snap
--- a/__snapshots__/test_j_s_o_n_with_special_characters.snap
+++ b/__snapshots__/test_j_s_o_n_with_special_characters.snap
@@ -6,12 +6,12 @@
version: 0.1.0
---
map[string]interface{}{
- "tabs": "col1\tcol2\tcol3",
"backslash": "path\\to\\file",
- "english": "Hello, World!",
- "unicode": "γγγ«γ‘γ― δΈη π",
"emoji": "π π π π π",
- "special_chars": "!@#$%^&*()_+-=[]{}|;:,.<>?",
+ "english": "Hello, World!",
"escaped": "quotes: \"double\" and 'single'",
"newlines": "line1\nline2\rline3\r\nline4",
+ "special_chars": "!@#$%^&*()_+-=[]{}|;:,.<>?",
+ "tabs": "col1\tcol2\tcol3",
+ "unicode": "γγγ«γ‘γ― δΈη π",
}
diff --git a/__snapshots__/test_j_s_o_n_with_various_types.snap b/__snapshots__/test_j_s_o_n_with_various_types.snap
--- a/__snapshots__/test_j_s_o_n_with_various_types.snap
+++ b/__snapshots__/test_j_s_o_n_with_various_types.snap
@@ -6,9 +6,6 @@
version: 0.1.0
---
map[string]interface{}{
- "float": 3.14159,
- "boolean_true": true,
- "null_value": nil,
"array": []interface{}{
1.0,
2.0,
@@ -16,16 +13,19 @@
"four",
5.5,
},
+ "boolean_false": false,
+ "boolean_true": true,
"empty_array": []interface{}{
},
"empty_object": map[string]interface{}{
},
"escaped_string": "line1\nline2\ttab",
- "string": "hello world",
+ "float": 3.14159,
"integer": 42.0,
- "boolean_false": false,
+ "null_value": nil,
"object": map[string]interface{}{
- "nested": "value",
"count": 10.0,
+ "nested": "value",
},
+ "string": "hello world",
}
diff --git a/__snapshots__/test_large_j_s_o_n.snap b/__snapshots__/test_large_j_s_o_n.snap
--- a/__snapshots__/test_large_j_s_o_n.snap
+++ b/__snapshots__/test_large_j_s_o_n.snap
@@ -6,50 +6,50 @@
version: 0.1.0
---
map[string]interface{}{
- "total": 1179.97,
- "status": "shipped",
"created_at": "2023-01-28T14:30:00Z",
- "shipped_at": "2023-02-01T10:00:00Z",
+ "customer_id": 42.0,
"delivered_at": nil,
"id": 1001.0,
- "customer_id": 42.0,
"products": []interface{}{
map[string]interface{}{
+ "description": "High-performance laptop",
+ "id": 1.0,
+ "in_stock": true,
+ "name": "Laptop",
"price": 999.99,
"stock": 5.0,
- "in_stock": true,
"tags": []interface{}{
"electronics",
"computers",
"laptops",
},
- "id": 1.0,
- "name": "Laptop",
- "description": "High-performance laptop",
},
map[string]interface{}{
- "name": "Mouse",
"description": "Wireless mouse",
+ "id": 2.0,
+ "in_stock": true,
+ "name": "Mouse",
"price": 29.99,
"stock": 50.0,
- "in_stock": true,
"tags": []interface{}{
"electronics",
"accessories",
},
- "id": 2.0,
},
map[string]interface{}{
"description": "Mechanical keyboard",
+ "id": 3.0,
+ "in_stock": false,
+ "name": "Keyboard",
"price": 149.99,
"stock": 0.0,
- "in_stock": false,
"tags": []interface{}{
"electronics",
"accessories",
},
- "id": 3.0,
- "name": "Keyboard",
},
},
+ "shipped_at": "2023-02-01T10:00:00Z",
+ "status": "shipped",
+ "total": 1179.97,
}
diff --git a/__snapshots__/test_multiple_complex_structures.snap b/__snapshots__/test_multiple_complex_structures.snap
--- a/__snapshots__/test_multiple_complex_structures.snap
+++ b/__snapshots__/test_multiple_complex_structures.snap
@@ -21,8 +21,8 @@
"moderator",
},
Metadata: map[string]interface{}{
- "verified": true,
"badge": "verified",
+ "verified": true,
},
},
{
@@ -39,8 +39,8 @@
"user",
},
Metadata: map[string]interface{}{
- "verified": false,
"avatar": "https://example.com/bob.jpg",
+ "verified": false,
},
},
{
@@ -58,8 +58,8 @@
"admin",
},
Metadata: map[string]interface{}{
- "verified": true,
"account_age_days": 365,
+ "verified": true,
},
},
}
diff --git a/__snapshots__/test_nested_maps_and_slices.snap b/__snapshots__/test_nested_maps_and_slices.snap
--- a/__snapshots__/test_nested_maps_and_slices.snap
+++ b/__snapshots__/test_nested_maps_and_slices.snap
@@ -6,6 +6,29 @@
version: 0.1.0
---
map[string]interface{}{
+ "posts": map[string]interface{}{
+ "categories": []string{
+ "tech",
+ "lifestyle",
+ "news",
+ },
+ "drafts": 5,
+ "published": 42,
+ },
+ "stats": map[string]interface{}{
+ "daily": map[string]interface{}{
+ "clicks": 320,
+ "conversions": map[string]interface{}{
+ "by_source": map[string]int{
+ "organic": 25,
+ "paid": 15,
+ "referral": 5,
+ },
+ "total": 45,
+ },
+ "views": 1500,
+ },
+ },
"users": map[string]interface{}{
"active": []map[string]interface{}{
{
@@ -23,29 +46,6 @@
{
"id": 3,
"name": "Charlie",
- },
- },
- },
- "posts": map[string]interface{}{
- "published": 42,
- "drafts": 5,
- "categories": []string{
- "tech",
- "lifestyle",
- "news",
- },
- },
- "stats": map[string]interface{}{
- "daily": map[string]interface{}{
- "views": 1500,
- "clicks": 320,
- "conversions": map[string]interface{}{
- "total": 45,
- "by_source": map[string]int{
- "paid": 15,
- "referral": 5,
- "organic": 25,
- },
},
},
},
diff --git a/__snapshots__/test_snap_j_s_o_n_array_of_objects.snap b/__snapshots__/test_snap_j_s_o_n_array_of_objects.snap
new file mode 100644
--- /dev/null
+++ b/__snapshots__/test_snap_j_s_o_n_array_of_objects.snap
@@ -0,0 +1,30 @@
+---
+title: SnapJSON Array of Objects
+test_name: TestSnapJSONArrayOfObjects
+file_path:
+func_name:
+version: 0.1.0
+---
+[]interface{}{
+ map[string]interface{}{
+ "id": 1.0,
+ "likes": 42.0,
+ "title": "First Post",
+ "type": "post",
+ "views": 150.0,
+ },
+ map[string]interface{}{
+ "id": 2.0,
+ "likes": 75.0,
+ "title": "Second Post",
+ "type": "post",
+ "views": 280.0,
+ },
+ map[string]interface{}{
+ "id": 3.0,
+ "likes": 120.0,
+ "title": "Third Post",
+ "type": "post",
+ "views": 450.0,
+ },
+}
diff --git a/__snapshots__/test_snap_j_s_o_n_basic.snap b/__snapshots__/test_snap_j_s_o_n_basic.snap
new file mode 100644
--- /dev/null
+++ b/__snapshots__/test_snap_j_s_o_n_basic.snap
@@ -0,0 +1,13 @@
+---
+title: SnapJSON Basic Object
+test_name: TestSnapJSONBasic
+file_path:
+func_name:
+version: 0.1.0
+---
+map[string]interface{}{
+ "age": 30.0,
+ "email": "john@example.com",
+ "name": "John Doe",
+ "verified": true,
+}
diff --git a/__snapshots__/test_snap_j_s_o_n_compact_format.snap b/__snapshots__/test_snap_j_s_o_n_compact_format.snap
new file mode 100644
--- /dev/null
+++ b/__snapshots__/test_snap_j_s_o_n_compact_format.snap
@@ -0,0 +1,17 @@
+---
+title: SnapJSON Compact Format
+test_name: TestSnapJSONCompactFormat
+file_path:
+func_name:
+version: 0.1.0
+---
+map[string]interface{}{
+ "id": 1.0,
+ "in_stock": true,
+ "name": "Product",
+ "price": 99.99,
+ "tags": []interface{}{
+ "electronics",
+ "gadgets",
+ },
+}
diff --git a/__snapshots__/test_snap_j_s_o_n_complex_a_p_i.snap b/__snapshots__/test_snap_j_s_o_n_complex_a_p_i.snap
new file mode 100644
--- /dev/null
+++ b/__snapshots__/test_snap_j_s_o_n_complex_a_p_i.snap
@@ -0,0 +1,43 @@
+---
+title: SnapJSON Complex API Response
+test_name: TestSnapJSONComplexAPI
+file_path:
+func_name:
+version: 0.1.0
+---
+map[string]interface{}{
+ "code": 200.0,
+ "data": map[string]interface{}{
+ "pagination": map[string]interface{}{
+ "page": 1.0,
+ "per_page": 10.0,
+ "total": 3.0,
+ "total_pages": 1.0,
+ },
+ "users": []interface{}{
+ map[string]interface{}{
+ "active": true,
+ "department": "Engineering",
+ "id": 1.0,
+ "name": "Alice",
+ "role": "admin",
+ },
+ map[string]interface{}{
+ "active": true,
+ "department": "Sales",
+ "id": 2.0,
+ "name": "Bob",
+ "role": "user",
+ },
+ map[string]interface{}{
+ "active": false,
+ "department": "Marketing",
+ "id": 3.0,
+ "name": "Charlie",
+ "role": "user",
+ },
+ },
+ },
+ "status": "success",
+ "timestamp": "2023-11-18T21:45:30Z",
+}
diff --git a/__snapshots__/test_snap_j_s_o_n_empty_structures.snap b/__snapshots__/test_snap_j_s_o_n_empty_structures.snap
new file mode 100644
--- /dev/null
+++ b/__snapshots__/test_snap_j_s_o_n_empty_structures.snap
@@ -0,0 +1,23 @@
+---
+title: SnapJSON Empty Structures
+test_name: TestSnapJSONEmptyStructures
+file_path:
+func_name:
+version: 0.1.0
+---
+map[string]interface{}{
+ "empty_array": []interface{}{
+ },
+ "empty_object": map[string]interface{}{
+ },
+ "empty_string": "",
+ "false_value": false,
+ "nested": map[string]interface{}{
+ "also_empty": map[string]interface{}{
+ },
+ "empty": []interface{}{
+ },
+ },
+ "null_value": nil,
+ "zero": 0.0,
+}
diff --git a/__snapshots__/test_snap_j_s_o_n_large_nested_structure.snap b/__snapshots__/test_snap_j_s_o_n_large_nested_structure.snap
new file mode 100644
--- /dev/null
+++ b/__snapshots__/test_snap_j_s_o_n_large_nested_structure.snap
@@ -0,0 +1,105 @@
+---
+title: SnapJSON Large Nested Structure
+test_name: TestSnapJSONLargeNestedStructure
+file_path:
+func_name:
+version: 0.1.0
+---
+map[string]interface{}{
+ "organization": map[string]interface{}{
+ "departments": []interface{}{
+ map[string]interface{}{
+ "manager": "Alice",
+ "name": "Engineering",
+ "teams": []interface{}{
+ map[string]interface{}{
+ "lead": "John",
+ "members": []interface{}{
+ map[string]interface{}{
+ "id": 1.0,
+ "level": "senior",
+ "name": "John",
+ },
+ map[string]interface{}{
+ "id": 2.0,
+ "level": "mid",
+ "name": "Jane",
+ },
+ },
+ "name": "Backend",
+ "projects": []interface{}{
+ map[string]interface{}{
+ "id": "proj_1",
+ "name": "API Service",
+ "status": "active",
+ },
+ map[string]interface{}{
+ "id": "proj_2",
+ "name": "Database Optimization",
+ "status": "planning",
+ },
+ },
+ },
+ map[string]interface{}{
+ "lead": "Bob",
+ "members": []interface{}{
+ map[string]interface{}{
+ "id": 3.0,
+ "level": "senior",
+ "name": "Bob",
+ },
+ map[string]interface{}{
+ "id": 4.0,
+ "level": "junior",
+ "name": "Carol",
+ },
+ },
+ "name": "Frontend",
+ "projects": []interface{}{
+ map[string]interface{}{
+ "id": "proj_3",
+ "name": "Web App",
+ "status": "active",
+ },
+ },
+ },
+ },
+ },
+ map[string]interface{}{
+ "manager": "Charlie",
+ "name": "Sales",
+ "teams": []interface{}{
+ map[string]interface{}{
+ "lead": "Dave",
+ "members": []interface{}{
+ map[string]interface{}{
+ "id": 5.0,
+ "level": "senior",
+ "name": "Dave",
+ },
+ map[string]interface{}{
+ "id": 6.0,
+ "level": "mid",
+ "name": "Eve",
+ },
+ },
+ "name": "Enterprise",
+ "projects": []interface{}{
+ },
+ },
+ },
+ },
+ },
+ "id": "org_123",
+ "metadata": map[string]interface{}{
+ "employees": 150.0,
+ "founded": "2020",
+ "locations": []interface{}{
+ "USA",
+ "EU",
+ "APAC",
+ },
+ },
+ "name": "TechCorp",
+ },
+}
diff --git a/__snapshots__/test_snap_j_s_o_n_mixed_types.snap b/__snapshots__/test_snap_j_s_o_n_mixed_types.snap
new file mode 100644
--- /dev/null
+++ b/__snapshots__/test_snap_j_s_o_n_mixed_types.snap
@@ -0,0 +1,42 @@
+---
+title: SnapJSON Mixed Types
+test_name: TestSnapJSONMixedTypes
+file_path:
+func_name:
+version: 0.1.0
+---
+map[string]interface{}{
+ "complex": []interface{}{
+ map[string]interface{}{
+ "id": 1.0,
+ "type": "user",
+ },
+ map[string]interface{}{
+ "id": 100.0,
+ "type": "post",
+ },
+ []interface{}{
+ 1.0,
+ 2.0,
+ 3.0,
+ },
+ "string",
+ nil,
+ },
+ "mixed_array": []interface{}{
+ "string",
+ 123.0,
+ 45.67,
+ true,
+ false,
+ nil,
+ map[string]interface{}{
+ "nested": "object",
+ },
+ []interface{}{
+ 1.0,
+ 2.0,
+ 3.0,
+ },
+ },
+}
diff --git a/__snapshots__/test_snap_j_s_o_n_real_world_example.snap b/__snapshots__/test_snap_j_s_o_n_real_world_example.snap
new file mode 100644
--- /dev/null
+++ b/__snapshots__/test_snap_j_s_o_n_real_world_example.snap
@@ -0,0 +1,85 @@
+---
+title: SnapJSON Real World Example
+test_name: TestSnapJSONRealWorldExample
+file_path:
+func_name:
+version: 0.1.0
+---
+map[string]interface{}{
+ "data": map[string]interface{}{
+ "product": map[string]interface{}{
+ "description": "High-quality wireless headphones with noise cancellation",
+ "id": "prod_12345",
+ "inventory": map[string]interface{}{
+ "available": 425.0,
+ "damaged": 25.0,
+ "reserved": 50.0,
+ "total": 500.0,
+ },
+ "name": "Premium Wireless Headphones",
+ "price": map[string]interface{}{
+ "amount": 199.99,
+ "currency": "USD",
+ "discount": 10.0,
+ "final_price": 179.99,
+ },
+ "ratings": map[string]interface{}{
+ "average": 4.5,
+ "breakdown": map[string]interface{}{
+ "1": 20.0,
+ "2": 30.0,
+ "3": 100.0,
+ "4": 350.0,
+ "5": 750.0,
+ },
+ "count": 1250.0,
+ },
+ "reviews": []interface{}{
+ map[string]interface{}{
+ "content": "Great sound quality and comfortable to wear.",
+ "created_at": "2023-11-15T10:30:00Z",
+ "helpful": 25.0,
+ "id": "rev_001",
+ "rating": 5.0,
+ "title": "Excellent product!",
+ "user": "john_doe",
+ },
+ map[string]interface{}{
+ "content": "Works well, could be cheaper.",
+ "created_at": "2023-11-10T14:20:00Z",
+ "helpful": 12.0,
+ "id": "rev_002",
+ "rating": 4.0,
+ "title": "Good but pricey",
+ "user": "jane_smith",
+ },
+ },
+ "sku": "PWH-001",
+ "specifications": map[string]interface{}{
+ "battery_life": "30 hours",
+ "colors": []interface{}{
+ "black",
+ "white",
+ "blue",
+ },
+ "warranty_months": 24.0,
+ "weight": "250g",
+ },
+ },
+ "related_products": []interface{}{
+ map[string]interface{}{
+ "id": "prod_12346",
+ "name": "Headphone Case",
+ "price": 29.99,
+ },
+ map[string]interface{}{
+ "id": "prod_12347",
+ "name": "Audio Cable",
+ "price": 14.99,
+ },
+ },
+ },
+ "request_id": "req_abc123def456",
+ "success": true,
+ "timestamp": "2023-11-18T22:00:00Z",
+}
diff --git a/__snapshots__/test_snap_j_s_o_n_simple_array.snap b/__snapshots__/test_snap_j_s_o_n_simple_array.snap
new file mode 100644
--- /dev/null
+++ b/__snapshots__/test_snap_j_s_o_n_simple_array.snap
@@ -0,0 +1,13 @@
+---
+title: SnapJSON Simple Array
+test_name: TestSnapJSONSimpleArray
+file_path:
+func_name:
+version: 0.1.0
+---
+[]interface{}{
+ "apple",
+ "banana",
+ "orange",
+ "grape",
+}
diff --git a/__snapshots__/test_snap_j_s_o_n_with_nested_objects.snap b/__snapshots__/test_snap_j_s_o_n_with_nested_objects.snap
new file mode 100644
--- /dev/null
+++ b/__snapshots__/test_snap_j_s_o_n_with_nested_objects.snap
@@ -0,0 +1,27 @@
+---
+title: SnapJSON Nested Objects
+test_name: TestSnapJSONWithNestedObjects
+file_path:
+func_name:
+version: 0.1.0
+---
+map[string]interface{}{
+ "created_at": "2023-06-15T10:30:00Z",
+ "user": map[string]interface{}{
+ "id": 42.0,
+ "permissions": []interface{}{
+ "read",
+ "write",
+ "admin",
+ },
+ "profile": map[string]interface{}{
+ "avatar": "https://example.com/avatar.jpg",
+ "settings": map[string]interface{}{
+ "language": "en",
+ "notifications": true,
+ "theme": "dark",
+ },
+ "username": "jane_smith",
+ },
+ },
+}
diff --git a/__snapshots__/test_snap_j_s_o_n_with_nulls.snap b/__snapshots__/test_snap_j_s_o_n_with_nulls.snap
new file mode 100644
--- /dev/null
+++ b/__snapshots__/test_snap_j_s_o_n_with_nulls.snap
@@ -0,0 +1,19 @@
+---
+title: SnapJSON With Nulls
+test_name: TestSnapJSONWithNulls
+file_path:
+func_name:
+version: 0.1.0
+---
+map[string]interface{}{
+ "category": nil,
+ "description": nil,
+ "id": 1.0,
+ "metadata": map[string]interface{}{
+ "created": "2023-01-01",
+ "deleted": nil,
+ "updated": nil,
+ },
+ "name": "Item",
+ "tags": nil,
+}
diff --git a/__snapshots__/test_snap_j_s_o_n_with_numbers.snap b/__snapshots__/test_snap_j_s_o_n_with_numbers.snap
new file mode 100644
--- /dev/null
+++ b/__snapshots__/test_snap_j_s_o_n_with_numbers.snap
@@ -0,0 +1,35 @@
+---
+title: SnapJSON With Numbers
+test_name: TestSnapJSONWithNumbers
+file_path:
+func_name:
+version: 0.1.0
+---
+map[string]interface{}{
+ "financial": map[string]interface{}{
+ "expenses": 750000.75,
+ "profit_margin": 0.2499,
+ "revenue": 1.0000005e+06,
+ },
+ "floats": []interface{}{
+ 0.0,
+ 3.14,
+ -2.5,
+ 0.001,
+ 0.000123,
+ 5.67e+10.0,
+ },
+ "integers": []interface{}{
+ 0.0,
+ 1.0,
+ -1.0,
+ 42.0,
+ -100.0,
+ 9.999999e+06.0,
+ },
+ "measurements": map[string]interface{}{
+ "distance": 1000.25,
+ "temperature": -40.5,
+ "weight": 0.5,
+ },
+}
diff --git a/__snapshots__/test_snap_j_s_o_n_with_special_characters.snap b/__snapshots__/test_snap_j_s_o_n_with_special_characters.snap
new file mode 100644
--- /dev/null
+++ b/__snapshots__/test_snap_j_s_o_n_with_special_characters.snap
@@ -0,0 +1,16 @@
+---
+title: SnapJSON With Special Characters
+test_name: TestSnapJSONWithSpecialCharacters
+file_path:
+func_name:
+version: 0.1.0
+---
+map[string]interface{}{
+ "escaped": "line1\nline2\ttab\rcarriage",
+ "html": "Content
",
+ "paths": "C:\\Users\\name\\Documents\\file.txt",
+ "quotes": "He said \"hello\" and she said 'goodbye'",
+ "regex": "^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$",
+ "special": "!@#$%^&*()_+-=[]{}|;:',.<>?/",
+ "unicode": "Hello δΈη π Ω
Ψ±ΨΨ¨Ψ§ ΠΡΠΈΠ²Π΅Ρ",
+}
diff --git a/__snapshots__/test_structure_with_empty_values.snap b/__snapshots__/test_structure_with_empty_values.snap
--- a/__snapshots__/test_structure_with_empty_values.snap
+++ b/__snapshots__/test_structure_with_empty_values.snap
@@ -29,8 +29,8 @@
"c",
},
Tags: map[string]string{
- "type": "test",
"env": "dev",
+ "type": "test",
},
OptionalID: &int(42),
Count: 3,
diff --git a/__snapshots__/test_structure_with_interface.snap b/__snapshots__/test_structure_with_interface.snap
--- a/__snapshots__/test_structure_with_interface.snap
+++ b/__snapshots__/test_structure_with_interface.snap
@@ -69,9 +69,9 @@
},
},
Meta: map[string]interface{}{
- "total_count": 10,
"page": 1,
"per_page": 20,
+ "total_count": 10,
},
},
}
--
tangled.sh