github.com/mutagen-io/mutagen@v0.18.0-rc1/pkg/encoding/common_test.go (about) 1 package encoding 2 3 import ( 4 "encoding/json" 5 "errors" 6 "os" 7 "testing" 8 ) 9 10 // testMessageJSON is a test structure to use for encoding tests using JSON. 11 type testMessageJSON struct { 12 // Name represents a person's name. 13 Name string 14 // Age represent's a person's age. 15 Age uint 16 } 17 18 const ( 19 // testMessageJSONString is the JSON-encoded form of the JSON test data. 20 testMessageJSONString = `{"Name":"George","Age":67}` 21 // testMessageJSONName is the JSON test name. 22 testMessageJSONName = "George" 23 // testMessageJSONAge is the JSON test age. 24 testMessageJSONAge = 67 25 ) 26 27 // TestLoadAndUnmarshalNonExistentPath tests that loading fails from a 28 // non-existent path. 29 func TestLoadAndUnmarshalNonExistentPath(t *testing.T) { 30 if !os.IsNotExist(LoadAndUnmarshal("/this/does/not/exist", nil)) { 31 t.Error("expected LoadAndUnmarshal to pass through non-existence errors") 32 } 33 } 34 35 // TestLoadAndUnmarshalDirectory tests that loading fails from a directory. 36 func TestLoadAndUnmarshalDirectory(t *testing.T) { 37 // Compute the path to the user's home directory. 38 homeDirectory, err := os.UserHomeDir() 39 if err != nil { 40 t.Fatal("unable to compute home directory:", err) 41 } 42 43 // Perform the test. 44 if LoadAndUnmarshal(homeDirectory, nil) == nil { 45 t.Error("expected LoadAndUnmarshal error when loading directory") 46 } 47 } 48 49 // TestLoadAndUnmarshalUnmarshalFail tests that unmarshaling fails if the 50 // unmarshaling callback fails. 51 func TestLoadAndUnmarshalUnmarshalFail(t *testing.T) { 52 // Create an empty temporary file and defer its cleanup. 53 file, err := os.CreateTemp("", "mutagen_encoding") 54 if err != nil { 55 t.Fatal("unable to create temporary file:", err) 56 } else if err = file.Close(); err != nil { 57 t.Fatal("unable to close temporary file:", err) 58 } 59 defer os.Remove(file.Name()) 60 61 // Create a broken unmarshaling function. 62 unmarshal := func(_ []byte) error { 63 return errors.New("unmarshal failed") 64 } 65 66 // Attempt to load and unmarshal using a broken unmarshaling function. 67 if LoadAndUnmarshal(file.Name(), unmarshal) == nil { 68 t.Error("expected LoadAndUnmarshal to return an error") 69 } 70 } 71 72 // TestLoadAndUnmarshal tests that loading and unmarshaling succeed. 73 func TestLoadAndUnmarshal(t *testing.T) { 74 // Write the test JSON to a temporary file and defer its cleanup. 75 file, err := os.CreateTemp("", "mutagen_encoding") 76 if err != nil { 77 t.Fatal("unable to create temporary file:", err) 78 } else if _, err = file.Write([]byte(testMessageJSONString)); err != nil { 79 t.Fatal("unable to write data to temporary file:", err) 80 } else if err = file.Close(); err != nil { 81 t.Fatal("unable to close temporary file:", err) 82 } 83 defer os.Remove(file.Name()) 84 85 // Create an unmarshaling function. 86 value := &testMessageJSON{} 87 unmarshal := func(data []byte) error { 88 return json.Unmarshal(data, value) 89 } 90 91 // Attempt to load and unmarshal. 92 if err := LoadAndUnmarshal(file.Name(), unmarshal); err != nil { 93 t.Fatal("LoadAndUnmarshal failed:", err) 94 } 95 96 // Verify test value names. 97 if value.Name != testMessageJSONName { 98 t.Error("test message name mismatch:", value.Name, "!=", testMessageJSONName) 99 } 100 if value.Age != testMessageJSONAge { 101 t.Error("test message age mismatch:", value.Age, "!=", testMessageJSONAge) 102 } 103 } 104 105 // TestMarshalAndSaveMarshalFail tests that marshaling fails if the marshaling 106 // callback fails. 107 func TestMarshalAndSaveMarshalFail(t *testing.T) { 108 // Create an empty temporary file and defer its cleanup. 109 file, err := os.CreateTemp("", "mutagen_encoding") 110 if err != nil { 111 t.Fatal("unable to create temporary file:", err) 112 } else if err = file.Close(); err != nil { 113 t.Fatal("unable to close temporary file:", err) 114 } 115 defer os.Remove(file.Name()) 116 117 // Create a broken marshaling function. 118 marshal := func() ([]byte, error) { 119 return nil, errors.New("marshal failed") 120 } 121 122 // Attempt to marshal and save using a broken unmarshaling function. 123 if MarshalAndSave(file.Name(), marshal) == nil { 124 t.Error("expected MarshalAndSave to return an error") 125 } 126 } 127 128 // TestMarshalAndSaveOverDirectory tests that saving over a directory fails. 129 func TestMarshalAndSaveOverDirectory(t *testing.T) { 130 // Create a marshaling function. 131 marshal := func() ([]byte, error) { 132 return []byte{0}, nil 133 } 134 135 // Attempt to marshal and save over a directory. 136 if MarshalAndSave(t.TempDir(), marshal) == nil { 137 t.Error("expected MarshalAndSave to return an error") 138 } 139 } 140 141 // TestMarshalAndSave tests that marshaling and saving succeed. 142 func TestMarshalAndSave(t *testing.T) { 143 // Create an empty temporary file and defer its cleanup. 144 file, err := os.CreateTemp("", "mutagen_encoding") 145 if err != nil { 146 t.Fatal("unable to create temporary file:", err) 147 } else if err = file.Close(); err != nil { 148 t.Fatal("unable to close temporary file:", err) 149 } 150 defer os.Remove(file.Name()) 151 152 // Create a marshaling function. 153 value := &testMessageJSON{Name: testMessageJSONName, Age: testMessageJSONAge} 154 marshal := func() ([]byte, error) { 155 return json.Marshal(value) 156 } 157 158 // Attempt to marshal and save. 159 if err := MarshalAndSave(file.Name(), marshal); err != nil { 160 t.Fatal("MarshalAndSave failed:", err) 161 } 162 163 // Read the contents of the file and ensure they match what's expected. 164 // TODO: Are we relying too much on the implementation details of the JSON 165 // encoder here? 166 contents, err := os.ReadFile(file.Name()) 167 if err != nil { 168 t.Fatal("unable to read saved contents:", err) 169 } else if string(contents) != testMessageJSONString { 170 t.Error("marshaled contents do not match expected:", string(contents), "!=", testMessageJSONString) 171 } 172 }