1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf.util; 32 33 import static com.google.common.truth.Truth.assertThat; 34 35 import com.google.common.collect.ImmutableList; 36 import com.google.protobuf.FieldMask; 37 import protobuf_unittest.UnittestProto.NestedTestAllTypes; 38 import protobuf_unittest.UnittestProto.TestAllTypes; 39 import junit.framework.TestCase; 40 41 /** Unit tests for {@link FieldMaskUtil}. */ 42 public class FieldMaskUtilTest extends TestCase { testIsValid()43 public void testIsValid() throws Exception { 44 assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload")); 45 assertFalse(FieldMaskUtil.isValid(NestedTestAllTypes.class, "nonexist")); 46 assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.optional_int32")); 47 assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.repeated_int32")); 48 assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.optional_nested_message")); 49 assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.repeated_nested_message")); 50 assertFalse(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.nonexist")); 51 52 assertTrue( 53 FieldMaskUtil.isValid(NestedTestAllTypes.class, FieldMaskUtil.fromString("payload"))); 54 assertFalse( 55 FieldMaskUtil.isValid(NestedTestAllTypes.class, FieldMaskUtil.fromString("nonexist"))); 56 assertFalse( 57 FieldMaskUtil.isValid( 58 NestedTestAllTypes.class, FieldMaskUtil.fromString("payload,nonexist"))); 59 60 assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.getDescriptor(), "payload")); 61 assertFalse(FieldMaskUtil.isValid(NestedTestAllTypes.getDescriptor(), "nonexist")); 62 63 assertTrue( 64 FieldMaskUtil.isValid( 65 NestedTestAllTypes.getDescriptor(), FieldMaskUtil.fromString("payload"))); 66 assertFalse( 67 FieldMaskUtil.isValid( 68 NestedTestAllTypes.getDescriptor(), FieldMaskUtil.fromString("nonexist"))); 69 70 assertTrue( 71 FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.optional_nested_message.bb")); 72 // Repeated fields cannot have sub-paths. 73 assertFalse( 74 FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.repeated_nested_message.bb")); 75 // Non-message fields cannot have sub-paths. 76 assertFalse(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.optional_int32.bb")); 77 } 78 testToString()79 public void testToString() throws Exception { 80 assertEquals("", FieldMaskUtil.toString(FieldMask.getDefaultInstance())); 81 FieldMask mask = FieldMask.newBuilder().addPaths("foo").build(); 82 assertEquals("foo", FieldMaskUtil.toString(mask)); 83 mask = FieldMask.newBuilder().addPaths("foo").addPaths("bar").build(); 84 assertEquals("foo,bar", FieldMaskUtil.toString(mask)); 85 86 // Empty field paths are ignored. 87 mask = 88 FieldMask.newBuilder() 89 .addPaths("") 90 .addPaths("foo") 91 .addPaths("") 92 .addPaths("bar") 93 .addPaths("") 94 .build(); 95 assertEquals("foo,bar", FieldMaskUtil.toString(mask)); 96 } 97 testFromString()98 public void testFromString() throws Exception { 99 FieldMask mask = FieldMaskUtil.fromString(""); 100 assertEquals(0, mask.getPathsCount()); 101 mask = FieldMaskUtil.fromString("foo"); 102 assertEquals(1, mask.getPathsCount()); 103 assertEquals("foo", mask.getPaths(0)); 104 mask = FieldMaskUtil.fromString("foo,bar.baz"); 105 assertEquals(2, mask.getPathsCount()); 106 assertEquals("foo", mask.getPaths(0)); 107 assertEquals("bar.baz", mask.getPaths(1)); 108 109 // Empty field paths are ignore. 110 mask = FieldMaskUtil.fromString(",foo,,bar,"); 111 assertEquals(2, mask.getPathsCount()); 112 assertEquals("foo", mask.getPaths(0)); 113 assertEquals("bar", mask.getPaths(1)); 114 115 // Check whether the field paths are valid if a class parameter is provided. 116 mask = FieldMaskUtil.fromString(NestedTestAllTypes.class, ",payload"); 117 118 try { 119 mask = FieldMaskUtil.fromString(NestedTestAllTypes.class, "payload,nonexist"); 120 fail("Exception is expected."); 121 } catch (IllegalArgumentException e) { 122 // Expected. 123 } 124 } 125 testFromFieldNumbers()126 public void testFromFieldNumbers() throws Exception { 127 FieldMask mask = FieldMaskUtil.fromFieldNumbers(TestAllTypes.class); 128 assertEquals(0, mask.getPathsCount()); 129 mask = 130 FieldMaskUtil.fromFieldNumbers( 131 TestAllTypes.class, TestAllTypes.OPTIONAL_INT32_FIELD_NUMBER); 132 assertEquals(1, mask.getPathsCount()); 133 assertEquals("optional_int32", mask.getPaths(0)); 134 mask = 135 FieldMaskUtil.fromFieldNumbers( 136 TestAllTypes.class, 137 TestAllTypes.OPTIONAL_INT32_FIELD_NUMBER, 138 TestAllTypes.OPTIONAL_INT64_FIELD_NUMBER); 139 assertEquals(2, mask.getPathsCount()); 140 assertEquals("optional_int32", mask.getPaths(0)); 141 assertEquals("optional_int64", mask.getPaths(1)); 142 143 try { 144 int invalidFieldNumber = 1000; 145 mask = FieldMaskUtil.fromFieldNumbers(TestAllTypes.class, invalidFieldNumber); 146 fail("Exception is expected."); 147 } catch (IllegalArgumentException expected) { 148 } 149 } 150 testToJsonString()151 public void testToJsonString() throws Exception { 152 FieldMask mask = FieldMask.getDefaultInstance(); 153 assertEquals("", FieldMaskUtil.toJsonString(mask)); 154 mask = FieldMask.newBuilder().addPaths("foo").build(); 155 assertEquals("foo", FieldMaskUtil.toJsonString(mask)); 156 mask = FieldMask.newBuilder().addPaths("foo.bar_baz").addPaths("").build(); 157 assertEquals("foo.barBaz", FieldMaskUtil.toJsonString(mask)); 158 mask = FieldMask.newBuilder().addPaths("foo").addPaths("bar_baz").build(); 159 assertEquals("foo,barBaz", FieldMaskUtil.toJsonString(mask)); 160 } 161 testFromJsonString()162 public void testFromJsonString() throws Exception { 163 FieldMask mask = FieldMaskUtil.fromJsonString(""); 164 assertEquals(0, mask.getPathsCount()); 165 mask = FieldMaskUtil.fromJsonString("foo"); 166 assertEquals(1, mask.getPathsCount()); 167 assertEquals("foo", mask.getPaths(0)); 168 mask = FieldMaskUtil.fromJsonString("foo.barBaz"); 169 assertEquals(1, mask.getPathsCount()); 170 assertEquals("foo.bar_baz", mask.getPaths(0)); 171 mask = FieldMaskUtil.fromJsonString("foo,barBaz"); 172 assertEquals(2, mask.getPathsCount()); 173 assertEquals("foo", mask.getPaths(0)); 174 assertEquals("bar_baz", mask.getPaths(1)); 175 } 176 testFromStringList()177 public void testFromStringList() throws Exception { 178 FieldMask mask = 179 FieldMaskUtil.fromStringList( 180 NestedTestAllTypes.class, ImmutableList.of("payload.repeated_nested_message", "child")); 181 assertThat(mask) 182 .isEqualTo( 183 FieldMask.newBuilder() 184 .addPaths("payload.repeated_nested_message") 185 .addPaths("child") 186 .build()); 187 188 mask = 189 FieldMaskUtil.fromStringList( 190 NestedTestAllTypes.getDescriptor(), 191 ImmutableList.of("payload.repeated_nested_message", "child")); 192 assertThat(mask) 193 .isEqualTo( 194 FieldMask.newBuilder() 195 .addPaths("payload.repeated_nested_message") 196 .addPaths("child") 197 .build()); 198 199 mask = 200 FieldMaskUtil.fromStringList(ImmutableList.of("payload.repeated_nested_message", "child")); 201 assertThat(mask) 202 .isEqualTo( 203 FieldMask.newBuilder() 204 .addPaths("payload.repeated_nested_message") 205 .addPaths("child") 206 .build()); 207 } 208 testUnion()209 public void testUnion() throws Exception { 210 // Only test a simple case here and expect 211 // {@link FieldMaskTreeTest#testAddFieldPath} to cover all scenarios. 212 FieldMask mask1 = FieldMaskUtil.fromString("foo,bar.baz,bar.quz"); 213 FieldMask mask2 = FieldMaskUtil.fromString("foo.bar,bar"); 214 FieldMask result = FieldMaskUtil.union(mask1, mask2); 215 assertEquals("bar,foo", FieldMaskUtil.toString(result)); 216 } 217 testUnion_usingVarArgs()218 public void testUnion_usingVarArgs() throws Exception { 219 FieldMask mask1 = FieldMaskUtil.fromString("foo"); 220 FieldMask mask2 = FieldMaskUtil.fromString("foo.bar,bar.quz"); 221 FieldMask mask3 = FieldMaskUtil.fromString("bar.quz"); 222 FieldMask mask4 = FieldMaskUtil.fromString("bar"); 223 FieldMask result = FieldMaskUtil.union(mask1, mask2, mask3, mask4); 224 assertEquals("bar,foo", FieldMaskUtil.toString(result)); 225 } 226 testSubstract()227 public void testSubstract() throws Exception { 228 // Only test a simple case here and expect 229 // {@link FieldMaskTreeTest#testRemoveFieldPath} to cover all scenarios. 230 FieldMask mask1 = FieldMaskUtil.fromString("foo,bar.baz,bar.quz"); 231 FieldMask mask2 = FieldMaskUtil.fromString("foo.bar,bar"); 232 FieldMask result = FieldMaskUtil.subtract(mask1, mask2); 233 assertEquals("foo", FieldMaskUtil.toString(result)); 234 } 235 testSubstract_usingVarArgs()236 public void testSubstract_usingVarArgs() throws Exception { 237 FieldMask mask1 = FieldMaskUtil.fromString("foo,bar.baz,bar.quz.bar"); 238 FieldMask mask2 = FieldMaskUtil.fromString("foo.bar,bar.baz.quz"); 239 FieldMask mask3 = FieldMaskUtil.fromString("bar.quz"); 240 FieldMask mask4 = FieldMaskUtil.fromString("foo,bar.baz"); 241 FieldMask result = FieldMaskUtil.subtract(mask1, mask2, mask3, mask4); 242 assertEquals("bar", FieldMaskUtil.toString(result)); 243 } 244 testIntersection()245 public void testIntersection() throws Exception { 246 // Only test a simple case here and expect 247 // {@link FieldMaskTreeTest#testIntersectFieldPath} to cover all scenarios. 248 FieldMask mask1 = FieldMaskUtil.fromString("foo,bar.baz,bar.quz"); 249 FieldMask mask2 = FieldMaskUtil.fromString("foo.bar,bar"); 250 FieldMask result = FieldMaskUtil.intersection(mask1, mask2); 251 assertEquals("bar.baz,bar.quz,foo.bar", FieldMaskUtil.toString(result)); 252 } 253 testMerge()254 public void testMerge() throws Exception { 255 // Only test a simple case here and expect 256 // {@link FieldMaskTreeTest#testMerge} to cover all scenarios. 257 NestedTestAllTypes source = 258 NestedTestAllTypes.newBuilder() 259 .setPayload(TestAllTypes.newBuilder().setOptionalInt32(1234)) 260 .build(); 261 NestedTestAllTypes.Builder builder = NestedTestAllTypes.newBuilder(); 262 FieldMaskUtil.merge(FieldMaskUtil.fromString("payload"), source, builder); 263 assertEquals(1234, builder.getPayload().getOptionalInt32()); 264 } 265 } 266