/** Confirms that {@code protoFiles} link correctly against {@code schema}. */ void validate(Schema schema, ImmutableList<ProfileFileElement> profileFiles) { List<String> errors = new ArrayList<>(); for (ProfileFileElement profileFile : profileFiles) { for (TypeConfigElement typeConfig : profileFile.typeConfigs()) { ProtoType type = importedType(ProtoType.get(typeConfig.type())); if (type == null) continue; Type resolvedType = schema.getType(type); if (resolvedType == null) { errors.add(String.format("unable to resolve %s (%s)", type, typeConfig.location())); continue; } String requiredImport = resolvedType.location().path(); if (!profileFile.imports().contains(requiredImport)) { errors.add(String.format("%s needs to import %s (%s)", typeConfig.location().path(), requiredImport, typeConfig.location())); } } } if (!errors.isEmpty()) { throw new SchemaException(errors); } }
@Test public void extendTypeNotImported() throws Exception { try { new RepoBuilder() .add("a.proto", "" + "package pa;\n" + "extend pb.B {\n" + " optional string a = 1;\n" + "}\n") .add("b.proto", "" + "package pb;\n" + "message B {\n" + " extensions 1;\n" + "}\n") .schema(); fail(); } catch (SchemaException expected) { assertThat(expected.getMessage()).isEqualTo("a.proto needs to import b.proto\n" + " for extend pb.B (/source/a.proto at 2:1)"); } }
throw new SchemaException(errors);
@Test public void fieldTypeNotImported() throws Exception { try { new RepoBuilder() .add("a.proto", "" + "package pa;\n" + "message A {\n" + " optional pb.B b = 1;\n" + "}\n") .add("b.proto", "" + "package pb;\n" + "message B {\n" + "}\n") .schema(); fail(); } catch (SchemaException expected) { assertThat(expected.getMessage()).isEqualTo("a.proto needs to import b.proto\n" + " for field b (/source/a.proto at 3:3)\n" + " in message pa.A (/source/a.proto at 2:1)"); } }
/** Confirms that {@code protoFiles} link correctly against {@code schema}. */ void validate(Schema schema, ImmutableList<AbstractProfileFileElement> profileFiles) { List<String> errors = new ArrayList<>(); for (AbstractProfileFileElement profileFile : profileFiles) { for (AbstractTypeConfigElement typeConfig : profileFile.typeConfigs()) { ProtoType type = importedType(ProtoType.get(typeConfig.type())); if (type == null) { continue; } Type resolvedType = schema.getType(type); if (resolvedType == null) { errors.add(String.format("unable to resolve %s (%s)", type, typeConfig.location())); continue; } String requiredImport = resolvedType.location().path(); if (!profileFile.imports().contains(requiredImport)) { errors.add(String.format("%s needs to import %s (%s)", typeConfig.location().path(), requiredImport, typeConfig.location())); } } } if (!errors.isEmpty()) { throw new SchemaException(errors); } }
@Test public void fieldMapTypeNotImported() throws Exception { try { new RepoBuilder() .add("a.proto", "" + "package pa;\n" + "message A {\n" + " map<string, pb.B> b = 1;\n" + "}\n") .add("b.proto", "" + "package pb;\n" + "message B {\n" + "}\n") .schema(); fail(); } catch (SchemaException expected) { assertThat(expected.getMessage()).isEqualTo("a.proto needs to import b.proto\n" + " for field b (/source/a.proto at 3:3)\n" + " in message pa.A (/source/a.proto at 2:1)"); } }
throw new SchemaException(errors);
@Test public void rpcTypeNotImported() throws Exception { try { new RepoBuilder() .add("a.proto", "" + "package pa;\n" + "service Service {\n" + " rpc Call (pb.B) returns (pb.B);\n" + "}\n") .add("b.proto", "" + "package pb;\n" + "message B {\n" + "}\n") .schema(); fail(); } catch (SchemaException expected) { assertThat(expected.getMessage()).isEqualTo("" + "a.proto needs to import b.proto\n" + " for rpc Call (/source/a.proto at 3:3)\n" + " in service pa.Service (/source/a.proto at 2:1)\n" + "a.proto needs to import b.proto\n" + " for rpc Call (/source/a.proto at 3:3)\n" + " in service pa.Service (/source/a.proto at 2:1)"); } }
throw new SchemaException(errors);
fail(); } catch (SchemaException expected) { assertThat(expected.getMessage()).isEqualTo("" + "tag is out of range: 0\n" + " for field a (/source/message.proto at 2:3)\n"
@Test public void transitiveImportNotFollowed() throws Exception { try { new RepoBuilder() .add("a.proto", "" + "package pa;\n" + "import \"b.proto\";\n" + "message A {\n" + " optional pc.C c = 1;\n" + "}\n") .add("b.proto", "" + "package pb;\n" + "import \"c.proto\";\n" + "message B {\n" + "}\n") .add("c.proto", "" + "package pc;\n" + "message C {\n" + "}\n") .schema(); fail(); } catch (SchemaException expected) { assertThat(expected.getMessage()).isEqualTo("a.proto needs to import c.proto\n" + " for field c (/source/a.proto at 4:3)\n" + " in message pa.A (/source/a.proto at 3:1)"); } }