| // Copyright (C) 2021 The Android Open Source Project | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //     http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | package sdk | 
 |  | 
 | import ( | 
 | 	"encoding/json" | 
 | 	"fmt" | 
 | 	"testing" | 
 |  | 
 | 	"android/soong/android" | 
 | ) | 
 |  | 
 | // Tests for build_release.go | 
 |  | 
 | var ( | 
 | 	// Some additional test specific releases that are added after the currently supported ones and | 
 | 	// so are treated as being for future releases. | 
 | 	buildReleaseFuture1 = initBuildRelease("F1") | 
 | 	buildReleaseFuture2 = initBuildRelease("F2") | 
 | ) | 
 |  | 
 | func TestNameToRelease(t *testing.T) { | 
 | 	t.Run("single release", func(t *testing.T) { | 
 | 		release, err := nameToRelease("S") | 
 | 		android.AssertDeepEquals(t, "errors", nil, err) | 
 | 		android.AssertDeepEquals(t, "release", buildReleaseS, release) | 
 | 	}) | 
 | 	t.Run("invalid release", func(t *testing.T) { | 
 | 		release, err := nameToRelease("A") | 
 | 		android.AssertDeepEquals(t, "release", (*buildRelease)(nil), release) | 
 | 		// Uses a wildcard in the error message to allow for additional build releases to be added to | 
 | 		// the supported set without breaking this test. | 
 | 		android.FailIfNoMatchingErrors(t, `unknown release "A", expected one of \[S,Tiramisu,UpsideDownCake,F1,F2,current\]`, []error{err}) | 
 | 	}) | 
 | } | 
 |  | 
 | func TestParseBuildReleaseSet(t *testing.T) { | 
 | 	t.Run("single release", func(t *testing.T) { | 
 | 		set, err := parseBuildReleaseSet("S") | 
 | 		android.AssertDeepEquals(t, "errors", nil, err) | 
 | 		android.AssertStringEquals(t, "set", "[S]", set.String()) | 
 | 	}) | 
 | 	t.Run("open range", func(t *testing.T) { | 
 | 		set, err := parseBuildReleaseSet("F1+") | 
 | 		android.AssertDeepEquals(t, "errors", nil, err) | 
 | 		android.AssertStringEquals(t, "set", "[F1,F2,current]", set.String()) | 
 | 	}) | 
 | 	t.Run("closed range", func(t *testing.T) { | 
 | 		set, err := parseBuildReleaseSet("S-F1") | 
 | 		android.AssertDeepEquals(t, "errors", nil, err) | 
 | 		android.AssertStringEquals(t, "set", "[S,Tiramisu,UpsideDownCake,F1]", set.String()) | 
 | 	}) | 
 | 	invalidAReleaseMessage := `unknown release "A", expected one of ` + allBuildReleaseSet.String() | 
 | 	t.Run("invalid release", func(t *testing.T) { | 
 | 		set, err := parseBuildReleaseSet("A") | 
 | 		android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set) | 
 | 		android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), invalidAReleaseMessage) | 
 | 	}) | 
 | 	t.Run("invalid release in open range", func(t *testing.T) { | 
 | 		set, err := parseBuildReleaseSet("A+") | 
 | 		android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set) | 
 | 		android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), invalidAReleaseMessage) | 
 | 	}) | 
 | 	t.Run("invalid release in closed range start", func(t *testing.T) { | 
 | 		set, err := parseBuildReleaseSet("A-S") | 
 | 		android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set) | 
 | 		android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), invalidAReleaseMessage) | 
 | 	}) | 
 | 	t.Run("invalid release in closed range end", func(t *testing.T) { | 
 | 		set, err := parseBuildReleaseSet("Tiramisu-A") | 
 | 		android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set) | 
 | 		android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), invalidAReleaseMessage) | 
 | 	}) | 
 | 	t.Run("invalid closed range reversed", func(t *testing.T) { | 
 | 		set, err := parseBuildReleaseSet("F1-S") | 
 | 		android.AssertDeepEquals(t, "set", (*buildReleaseSet)(nil), set) | 
 | 		android.AssertStringDoesContain(t, "errors", fmt.Sprint(err), `invalid closed range, start release "F1" is later than end release "S"`) | 
 | 	}) | 
 | } | 
 |  | 
 | func TestBuildReleaseSetContains(t *testing.T) { | 
 | 	t.Run("contains", func(t *testing.T) { | 
 | 		set, _ := parseBuildReleaseSet("F1-F2") | 
 | 		android.AssertBoolEquals(t, "set contains F1", true, set.contains(buildReleaseFuture1)) | 
 | 		android.AssertBoolEquals(t, "set does not contain S", false, set.contains(buildReleaseS)) | 
 | 		android.AssertBoolEquals(t, "set contains F2", true, set.contains(buildReleaseFuture2)) | 
 | 		android.AssertBoolEquals(t, "set does not contain T", false, set.contains(buildReleaseT)) | 
 | 	}) | 
 | } | 
 |  | 
 | func TestPropertyPrunerInvalidTag(t *testing.T) { | 
 | 	type brokenStruct struct { | 
 | 		Broken string `supported_build_releases:"A"` | 
 | 	} | 
 | 	type containingStruct struct { | 
 | 		Nested brokenStruct | 
 | 	} | 
 |  | 
 | 	t.Run("broken struct", func(t *testing.T) { | 
 | 		android.AssertPanicMessageContains(t, "error", "invalid `supported_build_releases` tag on Broken of *sdk.brokenStruct: unknown release \"A\"", func() { | 
 | 			newPropertyPrunerByBuildRelease(&brokenStruct{}, buildReleaseS) | 
 | 		}) | 
 | 	}) | 
 |  | 
 | 	t.Run("nested broken struct", func(t *testing.T) { | 
 | 		android.AssertPanicMessageContains(t, "error", "invalid `supported_build_releases` tag on Nested.Broken of *sdk.containingStruct: unknown release \"A\"", func() { | 
 | 			newPropertyPrunerByBuildRelease(&containingStruct{}, buildReleaseS) | 
 | 		}) | 
 | 	}) | 
 | } | 
 |  | 
 | func TestPropertyPrunerByBuildRelease(t *testing.T) { | 
 | 	type nested struct { | 
 | 		F1_only string `supported_build_releases:"F1"` | 
 | 	} | 
 |  | 
 | 	type mapped struct { | 
 | 		Default string | 
 | 		T_only  string `supported_build_releases:"Tiramisu"` | 
 | 	} | 
 |  | 
 | 	type testBuildReleasePruner struct { | 
 | 		Default      string | 
 | 		S_and_T_only string `supported_build_releases:"S-Tiramisu"` | 
 | 		T_later      string `supported_build_releases:"Tiramisu+"` | 
 | 		Nested       nested | 
 | 		Mapped       map[string]*mapped | 
 | 	} | 
 |  | 
 | 	inputFactory := func() testBuildReleasePruner { | 
 | 		return testBuildReleasePruner{ | 
 | 			Default:      "Default", | 
 | 			S_and_T_only: "S_and_T_only", | 
 | 			T_later:      "T_later", | 
 | 			Nested: nested{ | 
 | 				F1_only: "F1_only", | 
 | 			}, | 
 | 			Mapped: map[string]*mapped{ | 
 | 				"one": { | 
 | 					Default: "one-default", | 
 | 					T_only:  "one-t-only", | 
 | 				}, | 
 | 				"two": { | 
 | 					Default: "two-default", | 
 | 					T_only:  "two-t-only", | 
 | 				}, | 
 | 			}, | 
 | 		} | 
 | 	} | 
 |  | 
 | 	marshal := func(t interface{}) string { | 
 | 		bytes, err := json.MarshalIndent(t, "", "  ") | 
 | 		if err != nil { | 
 | 			panic(err) | 
 | 		} | 
 | 		return string(bytes) | 
 | 	} | 
 |  | 
 | 	assertJsonEquals := func(t *testing.T, expected, actual interface{}) { | 
 | 		t.Helper() | 
 | 		expectedJson := marshal(expected) | 
 | 		actualJson := marshal(actual) | 
 | 		if actualJson != expectedJson { | 
 | 			t.Errorf("test struct: expected:\n%s\n got:\n%s", expectedJson, actualJson) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	t.Run("target S", func(t *testing.T) { | 
 | 		testStruct := inputFactory() | 
 | 		pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseS) | 
 | 		pruner.pruneProperties(&testStruct) | 
 |  | 
 | 		expected := inputFactory() | 
 | 		expected.T_later = "" | 
 | 		expected.Nested.F1_only = "" | 
 | 		expected.Mapped["one"].T_only = "" | 
 | 		expected.Mapped["two"].T_only = "" | 
 | 		assertJsonEquals(t, expected, testStruct) | 
 | 	}) | 
 |  | 
 | 	t.Run("target T", func(t *testing.T) { | 
 | 		testStruct := inputFactory() | 
 | 		pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseT) | 
 | 		pruner.pruneProperties(&testStruct) | 
 |  | 
 | 		expected := inputFactory() | 
 | 		expected.Nested.F1_only = "" | 
 | 		assertJsonEquals(t, expected, testStruct) | 
 | 	}) | 
 |  | 
 | 	t.Run("target F1", func(t *testing.T) { | 
 | 		testStruct := inputFactory() | 
 | 		pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseFuture1) | 
 | 		pruner.pruneProperties(&testStruct) | 
 |  | 
 | 		expected := inputFactory() | 
 | 		expected.S_and_T_only = "" | 
 | 		expected.Mapped["one"].T_only = "" | 
 | 		expected.Mapped["two"].T_only = "" | 
 | 		assertJsonEquals(t, expected, testStruct) | 
 | 	}) | 
 |  | 
 | 	t.Run("target F2", func(t *testing.T) { | 
 | 		testStruct := inputFactory() | 
 | 		pruner := newPropertyPrunerByBuildRelease(&testStruct, buildReleaseFuture2) | 
 | 		pruner.pruneProperties(&testStruct) | 
 |  | 
 | 		expected := inputFactory() | 
 | 		expected.S_and_T_only = "" | 
 | 		expected.Nested.F1_only = "" | 
 | 		expected.Mapped["one"].T_only = "" | 
 | 		expected.Mapped["two"].T_only = "" | 
 | 		assertJsonEquals(t, expected, testStruct) | 
 | 	}) | 
 | } |