rust: validate existence of library source

While rust_bindgen modules may be interpreted as libraries, they do not
have a reference to the generated source until bindgen has been
executed. For now, ignore these modules.

Update the unit tests to cover the rust_bindgen case.

Test: SOONG_GEN_RUST_PROJECT=1 m nothing
Bug: 162881856
Change-Id: I329d0fe3d94b77d395c3684f55ab01544ff7c18f
diff --git a/rust/project_json_test.go b/rust/project_json_test.go
index 259a42f..8521940 100644
--- a/rust/project_json_test.go
+++ b/rust/project_json_test.go
@@ -15,6 +15,7 @@
 package rust
 
 import (
+	"encoding/json"
 	"io/ioutil"
 	"path/filepath"
 	"testing"
@@ -23,20 +24,12 @@
 	"android/soong/cc"
 )
 
-func TestProjectJson(t *testing.T) {
-	bp := `rust_library {
-		  name: "liba",
-		  srcs: ["src/lib.rs"],
-		  crate_name: "a"
-		}` + GatherRequiredDepsForTest()
-	env := map[string]string{"SOONG_GEN_RUST_PROJECT": "1"}
-	fs := map[string][]byte{
-		"foo.rs":     nil,
-		"src/lib.rs": nil,
-	}
-
+// testProjectJson run the generation of rust-project.json. It returns the raw
+// content of the generated file.
+func testProjectJson(t *testing.T, bp string, fs map[string][]byte) []byte {
 	cc.GatherRequiredFilesForTest(fs)
 
+	env := map[string]string{"SOONG_GEN_RUST_PROJECT": "1"}
 	config := android.TestArchConfig(buildDir, env, bp, fs)
 	ctx := CreateTestContext()
 	ctx.Register(config)
@@ -48,10 +41,81 @@
 	// The JSON file is generated via WriteFileToOutputDir. Therefore, it
 	// won't appear in the Output of the TestingSingleton. Manually verify
 	// it exists.
-	_, err := ioutil.ReadFile(filepath.Join(buildDir, "rust-project.json"))
+	content, err := ioutil.ReadFile(filepath.Join(buildDir, rustProjectJsonFileName))
 	if err != nil {
 		t.Errorf("rust-project.json has not been generated")
 	}
+	return content
+}
+
+// validateJsonCrates validates that content follows the basic structure of
+// rust-project.json. It returns the crates attribute if the validation
+// succeeded.
+// It uses an empty interface instead of relying on a defined structure to
+// avoid a strong dependency on our implementation.
+func validateJsonCrates(t *testing.T, rawContent []byte) []interface{} {
+	var content interface{}
+	err := json.Unmarshal(rawContent, &content)
+	if err != nil {
+		t.Errorf("Unable to parse the rust-project.json as JSON: %v", err)
+	}
+	root, ok := content.(map[string]interface{})
+	if !ok {
+		t.Errorf("Unexpected JSON format: %v", content)
+	}
+	if _, ok = root["crates"]; !ok {
+		t.Errorf("No crates attribute in rust-project.json: %v", root)
+	}
+	crates, ok := root["crates"].([]interface{})
+	if !ok {
+		t.Errorf("Unexpected crates format: %v", root["crates"])
+	}
+	return crates
+}
+
+func TestProjectJsonDep(t *testing.T) {
+	bp := `
+	rust_library {
+		name: "liba",
+		srcs: ["a/src/lib.rs"],
+		crate_name: "a"
+	}
+	rust_library {
+		name: "libb",
+		srcs: ["b/src/lib.rs"],
+		crate_name: "b",
+		rlibs: ["liba"],
+	}
+	` + GatherRequiredDepsForTest()
+	fs := map[string][]byte{
+		"a/src/lib.rs": nil,
+		"b/src/lib.rs": nil,
+	}
+	jsonContent := testProjectJson(t, bp, fs)
+	validateJsonCrates(t, jsonContent)
+}
+
+func TestProjectJsonBindGen(t *testing.T) {
+	bp := `
+	rust_library {
+		name: "liba",
+		srcs: ["src/lib.rs"],
+		rlibs: ["libbindings"],
+		crate_name: "a"
+	}
+	rust_bindgen {
+		name: "libbindings",
+		crate_name: "bindings",
+		source_stem: "bindings",
+		host_supported: true,
+		wrapper_src: "src/any.h",
+	}
+	` + GatherRequiredDepsForTest()
+	fs := map[string][]byte{
+		"src/lib.rs": nil,
+	}
+	jsonContent := testProjectJson(t, bp, fs)
+	validateJsonCrates(t, jsonContent)
 }
 
 func TestProjectJsonMultiVersion(t *testing.T) {