| // Copyright (C) 2015 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 validate |
| |
| import ( |
| "testing" |
| |
| "android.googlesource.com/platform/tools/gpu/api/apic/commands" |
| "android.googlesource.com/platform/tools/gpu/api/ast" |
| "android.googlesource.com/platform/tools/gpu/api/parser" |
| "android.googlesource.com/platform/tools/gpu/api/resolver" |
| "android.googlesource.com/platform/tools/gpu/api/semantic" |
| ) |
| |
| func compile(t *testing.T, source string) (*semantic.API, error) { |
| parsed, errs := parser.Parse(source) |
| if err := commands.CheckErrors(source, errs); err != nil { |
| return nil, err |
| } |
| compiled, errs := resolver.Resolve([]*ast.API{parsed}, nil, resolver.ASTToSemantic{}) |
| if err := commands.CheckErrors(source, errs); err != nil { |
| return nil, err |
| } |
| return compiled, nil |
| } |
| |
| type expectedError struct { |
| line int |
| column int |
| msg string |
| } |
| |
| type test struct { |
| source string |
| expected []expectedError |
| } |
| |
| func TestSimpleUnreachable(t *testing.T) { |
| expect := func(errs ...expectedError) []expectedError { |
| return errs |
| } |
| unreachable := func(l, c int) expectedError { |
| return expectedError{l, c, "Unreachable block"} |
| } |
| |
| for _, test := range []test{ |
| // Bool tests |
| {`s32 x = 0 |
| cmd void f() { |
| if (true) { x = 1 } |
| }`, expect()}, |
| |
| {`s32 x = 0 |
| cmd void f() { |
| if (true) { x = 1 } else {} |
| }`, expect()}, |
| |
| {`s32 x = 0 |
| cmd void f() { |
| if (false) {} else { x = 2 } |
| }`, expect()}, |
| |
| {`s32 x = 0 |
| cmd void f() { |
| a := false |
| if (a) { x = 1 } else { x = 2 } |
| }`, expect(unreachable(4, 16))}, |
| |
| {`s32 x = 0 |
| cmd void f() { |
| a := true |
| if (a) { x = 1 } else { x = 2 } |
| }`, expect(unreachable(4, 31))}, |
| |
| {`s32 x = 0 |
| cmd void f() { |
| a := true == false |
| if (a) { x = 1 } else { x = 2 } |
| }`, expect(unreachable(4, 16))}, |
| |
| {`s32 x = 0 |
| cmd void f() { |
| a := true && false |
| if (a) { x = 1 } else { x = 2 } |
| }`, expect(unreachable(4, 16))}, |
| |
| {`s32 x = 0 |
| cmd void f() { |
| a := true || false |
| if (a) { x = 1 } else { x = 2 } |
| }`, expect(unreachable(4, 31))}, |
| |
| {`s32 x = 0 |
| cmd void f(bool a) { |
| if (a) { if (!a) { x = 1 } } |
| if (!a) { if (a) { x = 1 } } |
| if (a) {} else if (a) { x = 1 } |
| if (!a) {} else if (!a) { x = 1 } |
| }`, expect( |
| unreachable(3, 26), |
| unreachable(4, 26), |
| unreachable(5, 31), |
| unreachable(6, 33), |
| )}, |
| |
| {`s32 x = 0 |
| cmd void f(bool v) { |
| assert(v) |
| if (v) { x = 1 } else { x = 2 } |
| }`, expect(unreachable(4, 31))}, |
| |
| // Uint tests |
| {`s32 x = 0 |
| cmd void f(u32 a) { |
| if (a > 5) { x = 1 } else { x = 2 } |
| }`, expect()}, |
| |
| {`s32 x = 0 |
| cmd void f() { |
| a := as!u32(5) |
| if (a > 4) { x = 1 } else { x = 2 } |
| if (a > 5) { x = 1 } else { x = 2 } |
| if (a > 6) { x = 1 } else { x = 2 } |
| if (4 > a) { x = 1 } else { x = 2 } |
| if (5 > a) { x = 1 } else { x = 2 } |
| if (6 > a) { x = 1 } else { x = 2 } |
| }`, expect( |
| unreachable(4, 35), |
| unreachable(5, 20), |
| unreachable(6, 20), |
| unreachable(7, 20), |
| unreachable(8, 20), |
| unreachable(9, 35), |
| )}, |
| |
| {`s32 x = 0 |
| cmd void f() { |
| a := as!u32(5) |
| if (a >= 4) { x = 1 } else { x = 2 } |
| if (a >= 5) { x = 1 } else { x = 2 } |
| if (a >= 6) { x = 1 } else { x = 2 } |
| if (4 >= a) { x = 1 } else { x = 2 } |
| if (5 >= a) { x = 1 } else { x = 2 } |
| if (6 >= a) { x = 1 } else { x = 2 } |
| }`, expect( |
| unreachable(4, 36), |
| unreachable(5, 36), |
| unreachable(6, 21), |
| unreachable(7, 21), |
| unreachable(8, 36), |
| unreachable(9, 36), |
| )}, |
| |
| {`s32 x = 0 |
| cmd void f() { |
| a := as!u32(5) |
| if (a < 4) { x = 1 } else { x = 2 } |
| if (a < 5) { x = 1 } else { x = 2 } |
| if (a < 6) { x = 1 } else { x = 2 } |
| if (4 < a) { x = 1 } else { x = 2 } |
| if (5 < a) { x = 1 } else { x = 2 } |
| if (6 < a) { x = 1 } else { x = 2 } |
| }`, expect( |
| unreachable(4, 20), |
| unreachable(5, 20), |
| unreachable(6, 35), |
| unreachable(7, 35), |
| unreachable(8, 20), |
| unreachable(9, 20), |
| )}, |
| |
| {`s32 x = 0 |
| cmd void f() { |
| a := as!u32(5) |
| if (a <= 4) { x = 1 } else { x = 2 } |
| if (a <= 5) { x = 1 } else { x = 2 } |
| if (a <= 6) { x = 1 } else { x = 2 } |
| if (4 <= a) { x = 1 } else { x = 2 } |
| if (5 <= a) { x = 1 } else { x = 2 } |
| if (6 <= a) { x = 1 } else { x = 2 } |
| }`, expect( |
| unreachable(4, 21), |
| unreachable(5, 36), |
| unreachable(6, 36), |
| unreachable(7, 36), |
| unreachable(8, 36), |
| unreachable(9, 21), |
| )}, |
| |
| {`s32 x = 0 |
| cmd void f() { |
| a := as!u32(5) |
| if (a == 4) { x = 1 } else { x = 2 } |
| if (a == 5) { x = 1 } else { x = 2 } |
| if (a == 6) { x = 1 } else { x = 2 } |
| }`, expect( |
| unreachable(4, 21), |
| unreachable(5, 36), |
| unreachable(6, 21), |
| )}, |
| } { |
| api, err := compile(t, test.source) |
| if err != nil { |
| t.Errorf("API compile failed with %s", err) |
| return |
| } |
| if api == nil { |
| t.Errorf("API compiled but was nil") |
| return |
| } |
| got := noUnreachables(api) |
| ok := true |
| if len(got) == len(test.expected) { |
| for i := range got { |
| l, c := got[i].At.Token().Cursor() |
| if l != test.expected[i].line || |
| c != test.expected[i].column || |
| got[i].Message != test.expected[i].msg { |
| ok = false |
| } |
| } |
| } else { |
| ok = false |
| } |
| |
| if !ok { |
| t.Errorf("Errors were not as expected for:\n%s\n\n Got: %+v, Wanted: %+v", test.source, got, test.expected) |
| } |
| } |
| } |