Add support for write-only attributes (#146)

diff --git a/schemas.go b/schemas.go
index f6acc1f..13d0d38 100644
--- a/schemas.go
+++ b/schemas.go
@@ -230,6 +230,10 @@
 	// in logs. Future versions of Terraform may encrypt or otherwise
 	// treat these values with greater care than non-sensitive fields.
 	Sensitive bool `json:"sensitive,omitempty"`
+
+	// If true, this attribute is write only and its value will not be
+	// persisted in artifacts such as plan files or state.
+	WriteOnly bool `json:"write_only,omitempty"`
 }
 
 // jsonSchemaAttribute describes an attribute within a schema block
@@ -249,6 +253,7 @@
 	Optional            bool                       `json:"optional,omitempty"`
 	Computed            bool                       `json:"computed,omitempty"`
 	Sensitive           bool                       `json:"sensitive,omitempty"`
+	WriteOnly           bool                       `json:"write_only,omitempty"`
 }
 
 func (as *SchemaAttribute) MarshalJSON() ([]byte, error) {
@@ -261,6 +266,7 @@
 		Optional:            as.Optional,
 		Computed:            as.Computed,
 		Sensitive:           as.Sensitive,
+		WriteOnly:           as.WriteOnly,
 	}
 	if as.AttributeType != cty.NilType {
 		attrTy, _ := as.AttributeType.MarshalJSON()
diff --git a/schemas_test.go b/schemas_test.go
index dddf5e1..d659e79 100644
--- a/schemas_test.go
+++ b/schemas_test.go
@@ -10,24 +10,47 @@
 )
 
 func TestProviderSchemasValidate(t *testing.T) {
-	f, err := os.Open("testdata/basic/schemas.json")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer f.Close()
-
-	var schemas *ProviderSchemas
-	if err := json.NewDecoder(f).Decode(&schemas); err != nil {
-		t.Fatal(err)
+	cases := map[string]struct {
+		testDataPath string
+	}{
+		"a basic provider schema is validated": {
+			testDataPath: "testdata/basic/schemas.json",
+		},
+		"a provider schema including functions is validated": {
+			testDataPath: "testdata/functions/schemas.json",
+		},
+		"a provider schema including ephemeral resources is validated": {
+			testDataPath: "testdata/ephemeral_resources/schemas.json",
+		},
+		"a provider schema including a resource with write-only attribute(s) is validated": {
+			testDataPath: "testdata/write_only_attribute_on_resource/schemas.json",
+		},
 	}
 
-	if err := schemas.Validate(); err != nil {
-		t.Fatal(err)
+	for tn, tc := range cases {
+		t.Run(tn, func(t *testing.T) {
+			f, err := os.Open(tc.testDataPath)
+			if err != nil {
+				t.Fatal(err)
+			}
+			defer f.Close()
+
+			var schemas *ProviderSchemas
+			if err := json.NewDecoder(f).Decode(&schemas); err != nil {
+				t.Fatal(err)
+			}
+
+			if err := schemas.Validate(); err != nil {
+				t.Fatal(err)
+			}
+		})
 	}
 }
 
-func TestProviderSchemasValidate_functions(t *testing.T) {
-	f, err := os.Open("testdata/functions/schemas.json")
+// TestProviderSchemas_writeOnlyAttribute asserts that write-only attributes in a resource in a
+// provider schema JSON file are marked as WriteOnly once decoded into a ProviderSchemas struct
+func TestProviderSchemas_writeOnlyAttribute(t *testing.T) {
+	f, err := os.Open("testdata/write_only_attribute_on_resource/schemas.json")
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -38,41 +61,11 @@
 		t.Fatal(err)
 	}
 
-	if err := schemas.Validate(); err != nil {
-		t.Fatal(err)
+	resourceSchema := schemas.Schemas["terraform.io/builtin/terraform"].ResourceSchemas["terraform_example"]
+	if resourceSchema.Block.Attributes["wo_attr"].WriteOnly != true {
+		t.Fatal("expected terraform_example.wo_attr to be marked as write-only")
 	}
-}
-
-func TestProviderSchemasValidate_ephemeralResources(t *testing.T) {
-	f, err := os.Open("testdata/ephemeral_resources/schemas.json")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer f.Close()
-
-	var schemas *ProviderSchemas
-	if err := json.NewDecoder(f).Decode(&schemas); err != nil {
-		t.Fatal(err)
-	}
-
-	if err := schemas.Validate(); err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestProviderSchemasValidate_nestedAttributes(t *testing.T) {
-	f, err := os.Open("testdata/nested_attributes/schemas.json")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer f.Close()
-
-	var schemas *ProviderSchemas
-	if err := json.NewDecoder(f).Decode(&schemas); err != nil {
-		t.Fatal(err)
-	}
-
-	if err := schemas.Validate(); err != nil {
-		t.Fatal(err)
+	if resourceSchema.Block.Attributes["foo"].WriteOnly != false {
+		t.Fatal("expected terraform_example.foo to not be marked as write-only")
 	}
 }
diff --git a/testdata/write_only_attribute_on_resource/schemas.json b/testdata/write_only_attribute_on_resource/schemas.json
new file mode 100644
index 0000000..e8c9146
--- /dev/null
+++ b/testdata/write_only_attribute_on_resource/schemas.json
@@ -0,0 +1 @@
+{"format_version":"1.0","provider_schemas":{"terraform.io/builtin/terraform":{"provider":{"version":0},"resource_schemas":{"terraform_example":{"version":0,"block":{"attributes":{"foo":{"type":"string","description_kind":"plain","optional":true},"wo_attr":{"type":"string","description_kind":"plain","optional":true,"write_only":true}},"description_kind":"plain"}}}}}}