diff --git a/__snapshots__/test_complex_j_s_o_n_structure.snap b/__snapshots__/test_complex_j_s_o_n_structure.snap index c67daa3..ca9333f 100644 --- a/__snapshots__/test_complex_j_s_o_n_structure.snap +++ b/__snapshots__/test_complex_j_s_o_n_structure.snap @@ -7,9 +7,11 @@ version: 0.1.0 --- 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 @@ map[string]interface{}{ "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,50 +29,49 @@ map[string]interface{}{ "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", + }, + "email": map[string]interface{}{ + "format": "email", + "type": "string", + }, + "id": map[string]interface{}{ + "type": "integer", }, "roles": map[string]interface{}{ - "type": "array", "items": map[string]interface{}{ "type": "string", }, - }, - "id": map[string]interface{}{ - "type": "integer", + "type": "array", }, "username": map[string]interface{}{ "type": "string", }, - "email": map[string]interface{}{ - "type": "string", - "format": "email", - }, }, "required": []interface{}{ "id", @@ -81,5 +80,6 @@ map[string]interface{}{ }, }, }, + "version": "2.0", }, } diff --git a/__snapshots__/test_complex_nested_structure.snap b/__snapshots__/test_complex_nested_structure.snap index 880314f..989bf92 100644 --- a/__snapshots__/test_complex_nested_structure.snap +++ b/__snapshots__/test_complex_nested_structure.snap @@ -26,12 +26,12 @@ freeze_test.Post{ }, 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 index e1da1fa..e96d1f9 100644 --- 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 @@ func_name: 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 index c8df1c0..756c0ce 100644 --- 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 @@ version: 0.1.0 --- []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 index f861e73..42f3bc2 100644 --- a/__snapshots__/test_j_s_o_n_numbers.snap +++ b/__snapshots__/test_j_s_o_n_numbers.snap @@ -6,20 +6,20 @@ func_name: 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 index 9b54a48..be50307 100644 --- a/__snapshots__/test_j_s_o_n_object.snap +++ b/__snapshots__/test_j_s_o_n_object.snap @@ -6,22 +6,22 @@ func_name: version: 0.1.0 --- map[string]interface{}{ + "message": nil, + "status": "success", "user": map[string]interface{}{ - "roles": []interface{}{ - "user", - "admin", - }, "created_at": "2023-01-15T10:30:00Z", - "id": 1.0, - "username": "john_doe", "email": "john@example.com", + "id": 1.0, "profile": map[string]interface{}{ + "bio": "Software engineer", "first_name": "John", "last_name": "Doe", - "bio": "Software engineer", "verified": true, }, + "roles": []interface{}{ + "user", + "admin", + }, + "username": "john_doe", }, - "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 index 090e891..30d1f6f 100644 --- 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 @@ map[string]interface{}{ "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 index b6ef0ca..92d21bb 100644 --- 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 @@ func_name: 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 index e3008bd..1271969 100644 --- 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 @@ func_name: 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 @@ map[string]interface{}{ "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 index acb1a88..2a3c3a9 100644 --- a/__snapshots__/test_large_j_s_o_n.snap +++ b/__snapshots__/test_large_j_s_o_n.snap @@ -6,50 +6,50 @@ func_name: 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 index af615ac..0017c39 100644 --- a/__snapshots__/test_multiple_complex_structures.snap +++ b/__snapshots__/test_multiple_complex_structures.snap @@ -21,8 +21,8 @@ version: 0.1.0 "moderator", }, Metadata: map[string]interface{}{ - "verified": true, "badge": "verified", + "verified": true, }, }, { @@ -39,8 +39,8 @@ version: 0.1.0 "user", }, Metadata: map[string]interface{}{ - "verified": false, "avatar": "https://example.com/bob.jpg", + "verified": false, }, }, { @@ -58,8 +58,8 @@ version: 0.1.0 "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 index a68f5db..187ca8b 100644 --- a/__snapshots__/test_nested_maps_and_slices.snap +++ b/__snapshots__/test_nested_maps_and_slices.snap @@ -6,6 +6,29 @@ func_name: 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{}{ { @@ -26,27 +49,4 @@ map[string]interface{}{ }, }, }, - "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 index 0000000..0d01768 --- /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 index 0000000..c070c54 --- /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 index 0000000..2e7b4c5 --- /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 index 0000000..01f27fc --- /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 index 0000000..af8f254 --- /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 index 0000000..e2fe139 --- /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 index 0000000..1ecf623 --- /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 index 0000000..a981571 --- /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 index 0000000..6ba0efa --- /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 index 0000000..95aae1e --- /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 index 0000000..c9a0649 --- /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 index 0000000..6a3e167 --- /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 index 0000000..689cceb --- /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 index 84e1db3..5850fcd 100644 --- a/__snapshots__/test_structure_with_empty_values.snap +++ b/__snapshots__/test_structure_with_empty_values.snap @@ -29,8 +29,8 @@ version: 0.1.0 "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 index 5f38d02..c4c40bc 100644 --- a/__snapshots__/test_structure_with_interface.snap +++ b/__snapshots__/test_structure_with_interface.snap @@ -69,9 +69,9 @@ version: 0.1.0 }, }, Meta: map[string]interface{}{ - "total_count": 10, "page": 1, "per_page": 20, + "total_count": 10, }, }, } diff --git a/freeze.go b/freeze.go index 1e54453..fe6f1b1 100644 --- a/freeze.go +++ b/freeze.go @@ -1,6 +1,7 @@ package freeze import ( + "encoding/json" "fmt" "github.com/kortschak/utter" @@ -15,6 +16,7 @@ const version = "0.1.0" // 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) { @@ -22,6 +24,23 @@ func SnapString(t testingT, title string, content string) { 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) +} + func Snap(t testingT, title string, values ...any) { t.Helper() content := formatValues(values...) diff --git a/freeze_test.go b/freeze_test.go index 26c81d4..1fbe932 100644 --- a/freeze_test.go +++ b/freeze_test.go @@ -941,6 +941,373 @@ func TestJSONWithMixedArrays(t *testing.T) { freeze.Snap(t, "JSON with Mixed Arrays", data) } +// ============================================================================ +// 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 // ============================================================================