| // Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| import 'dart:core'; | |
| import 'dart:core' as type; | |
| import 'package:_fe_analyzer_shared/src/messages/codes.dart'; | |
| import 'package:_fe_analyzer_shared/src/util/stack_checker.dart'; | |
| import 'package:_fe_analyzer_shared/src/util/value_kind.dart'; | |
| final Uri dummyUri = Uri.parse('dummy:test'); | |
| const int dummyOffset = -1; | |
| class StackCheckerTester with StackChecker { | |
| final List<Object?> stack; | |
| StackCheckerTester(List<Object?> stack) : stack = stack.reversed.toList(); | |
| @override | |
| Never internalProblem(Message message, int charOffset, Uri uri) { | |
| throw message; | |
| } | |
| @override | |
| Object? lookupStack(int index) { | |
| return stack[stack.length - index - 1]; | |
| } | |
| @override | |
| int get stackHeight => stack.length; | |
| } | |
| class ValueKinds { | |
| static const ValueKind bool = const SingleValueKind<type.bool>(); | |
| static const ValueKind int = const SingleValueKind<type.int>(); | |
| static const ValueKind String = const SingleValueKind<type.String>(); | |
| } | |
| void testBase({ | |
| required List<Object?> stack, | |
| required int base, | |
| String? expectedMessage, | |
| }) { | |
| print('--- stack=${stack}, base=$base ---\n'); | |
| try { | |
| StackCheckerTester( | |
| stack, | |
| ).checkStackBaseStateForAssert(dummyUri, dummyOffset, base); | |
| if (expectedMessage != null) { | |
| throw 'Expected failure on stack=${stack}, base=$base'; | |
| } | |
| } on Message catch (message) { | |
| print(message.problemMessage); | |
| if (expectedMessage != null) { | |
| if (message.problemMessage != expectedMessage) { | |
| throw 'Unexpected message:\n' | |
| 'Expected:\n\n$expectedMessage\n\n' | |
| 'Actual:\n\n${message.problemMessage}'; | |
| } | |
| } else { | |
| throw 'Unexpected failure on stack=${stack}, base=$base'; | |
| } | |
| } | |
| } | |
| void testStack({ | |
| required List<Object?> stack, | |
| required List<ValueKind> expected, | |
| int? base, | |
| String? expectedMessage, | |
| }) { | |
| print( | |
| '--- stack=${stack}, ' | |
| 'expected=$expected, base=$base ---\n', | |
| ); | |
| try { | |
| StackCheckerTester( | |
| stack, | |
| ).checkStackStateForAssert(dummyUri, dummyOffset, expected, base: base); | |
| if (expectedMessage != null) { | |
| throw 'Expected failure on stack=${stack}, ' | |
| 'expected=$expected, base=$base'; | |
| } | |
| } on Message catch (message) { | |
| print(message.problemMessage); | |
| if (expectedMessage != null) { | |
| if (message.problemMessage != expectedMessage) { | |
| throw 'Unexpected message:\n' | |
| 'Expected:\n\n$expectedMessage\n\n' | |
| 'Actual:\n\n${message.problemMessage}'; | |
| } | |
| } else { | |
| throw 'Unexpected failure on stack=${stack}, ' | |
| 'expected=$expected, base=$base'; | |
| } | |
| } | |
| } | |
| main() { | |
| // Empty stack. | |
| testBase(stack: [], base: 0); | |
| // More elements than needed 0. | |
| testBase(stack: ['foo', 0], base: 0); | |
| // More elements than needed 0. | |
| testBase(stack: ['foo', 0], base: 1); | |
| // More elements than needed 0. | |
| testBase(stack: ['foo', 0], base: 2); | |
| // Too few elements 1. | |
| testBase( | |
| stack: [], | |
| base: -1, | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Too few elements on stack. Expected 1, found 0.''', | |
| ); | |
| // Too few elements 2. | |
| testBase( | |
| stack: ['foo', 0], | |
| base: -2, | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Too few elements on stack. Expected 4, found 2.''', | |
| ); | |
| // Empty stack. | |
| testStack(stack: [], expected: []); | |
| // More elements than needed 0. | |
| testStack(stack: ['foo', 0], expected: []); | |
| // More elements than needed 1. | |
| testStack(stack: ['foo', 0], expected: [ValueKinds.String]); | |
| // Exactly elements needed. | |
| testStack(stack: ['foo', 0], expected: [ValueKinds.String, ValueKinds.int]); | |
| // Too few on stack 1. | |
| testStack( | |
| stack: [], | |
| expected: [ValueKinds.String], | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Too few elements on stack. Expected 1, found 0. | |
| 0: String *--- | |
| 1: --- --- | |
| ''', | |
| ); | |
| // Too few on stack 2. | |
| testStack( | |
| stack: [], | |
| expected: [ValueKinds.String, ValueKinds.int], | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Too few elements on stack. Expected 2, found 0. | |
| 0: String *--- | |
| 1: int *--- | |
| 2: --- --- | |
| ''', | |
| ); | |
| // Too few on stack 3. | |
| testStack( | |
| stack: ['foo', 0], | |
| expected: [ValueKinds.String, ValueKinds.int, ValueKinds.bool], | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Too few elements on stack. Expected 3, found 2. | |
| 0: String foo (String) | |
| 1: int 0 (int) | |
| 2: bool *--- | |
| 3: --- --- | |
| ''', | |
| ); | |
| // Wrong kind 1. | |
| testStack( | |
| stack: ['foo', 0], | |
| expected: [ValueKinds.int, ValueKinds.int], | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Unexpected element kind(s). | |
| 0: int *foo (String) | |
| 1: int 0 (int) | |
| 2: --- --- | |
| ''', | |
| ); | |
| // Wrong kind 2. | |
| testStack( | |
| stack: ['foo', 0], | |
| expected: [ValueKinds.String, ValueKinds.String], | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Unexpected element kind(s). | |
| 0: String foo (String) | |
| 1: String *0 (int) | |
| 2: --- --- | |
| ''', | |
| ); | |
| // Wrong kind 3. | |
| testStack( | |
| stack: ['foo', 0], | |
| expected: [ValueKinds.int, ValueKinds.String], | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Unexpected element kind(s). | |
| 0: int *foo (String) | |
| 1: String *0 (int) | |
| 2: --- --- | |
| ''', | |
| ); | |
| // Too few and wrong kind. | |
| testStack( | |
| stack: ['foo'], | |
| expected: [ValueKinds.int, ValueKinds.String], | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Too few elements on stack. Expected 2, found 1. | |
| Unexpected element kind(s). | |
| 0: int *foo (String) | |
| 1: String *--- | |
| 2: --- --- | |
| ''', | |
| ); | |
| // Expect empty. | |
| testStack(stack: [], expected: [], base: 0); | |
| // Too few on stack 1. | |
| testStack( | |
| stack: [], | |
| expected: [ValueKinds.String], | |
| base: 0, | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Too few elements on stack. Expected 1, found 0. | |
| *: String *--- | |
| > 0: --- --- | |
| ''', | |
| ); | |
| // Too few on stack 2. | |
| testStack( | |
| stack: [], | |
| expected: [ValueKinds.String, ValueKinds.int], | |
| base: 0, | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Too few elements on stack. Expected 2, found 0. | |
| *: String *--- | |
| *: int *--- | |
| > 0: --- --- | |
| ''', | |
| ); | |
| // Too few on stack 3. | |
| testStack( | |
| stack: ['foo', 0], | |
| expected: [ValueKinds.String, ValueKinds.int, ValueKinds.bool], | |
| base: 0, | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Too few elements on stack. Expected 3, found 2. | |
| Unexpected element kind(s). | |
| *: String *--- | |
| 0: int *foo (String) | |
| 1: bool *0 (int) | |
| > 2: --- --- | |
| ''', | |
| ); | |
| // Wrong kind 1. | |
| testStack( | |
| stack: ['foo', 0], | |
| expected: [ValueKinds.int, ValueKinds.int], | |
| base: 0, | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Unexpected element kind(s). | |
| 0: int *foo (String) | |
| 1: int 0 (int) | |
| > 2: --- --- | |
| ''', | |
| ); | |
| // Wrong kind 2. | |
| testStack( | |
| stack: ['foo', 0], | |
| expected: [ValueKinds.String, ValueKinds.String], | |
| base: 0, | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Unexpected element kind(s). | |
| 0: String foo (String) | |
| 1: String *0 (int) | |
| > 2: --- --- | |
| ''', | |
| ); | |
| // Wrong kind 3. | |
| testStack( | |
| stack: ['foo', 0], | |
| expected: [ValueKinds.int, ValueKinds.String], | |
| base: 0, | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Unexpected element kind(s). | |
| 0: int *foo (String) | |
| 1: String *0 (int) | |
| > 2: --- --- | |
| ''', | |
| ); | |
| // Too many 1, expect empty. | |
| testStack( | |
| stack: ['foo', 0], | |
| expected: [], | |
| base: 0, | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Too many elements on stack. Expected 0, found 2. | |
| 0: foo (String) | |
| 1: 0 (int) | |
| > 2: --- --- | |
| ''', | |
| ); | |
| // Too many 2. | |
| testStack( | |
| stack: ['foo', 0], | |
| expected: [ValueKinds.String], | |
| base: 0, | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Too many elements on stack. Expected 1, found 2. | |
| Unexpected element kind(s). | |
| 0: foo (String) | |
| 1: String *0 (int) | |
| > 2: --- --- | |
| ''', | |
| ); | |
| // Matching stack, relative base. | |
| testStack( | |
| stack: ['foo', 0], | |
| expected: [ValueKinds.String, ValueKinds.int], | |
| base: 0, | |
| ); | |
| // Expect empty, relative base. | |
| testStack(stack: ['foo', 0], expected: [], base: 2); | |
| // More elements but matching stack, relative base, 1. | |
| testStack(stack: ['foo', 0, true], expected: [ValueKinds.String], base: 2); | |
| // More elements but matching stack, relative base, 2. | |
| testStack( | |
| stack: ['foo', 0, true, 'bar'], | |
| expected: [ValueKinds.String, ValueKinds.int], | |
| base: 2, | |
| ); | |
| // Too few 1, relative base. | |
| testStack( | |
| stack: ['foo', 0], | |
| expected: [ValueKinds.String], | |
| base: 2, | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Too few elements on stack. Expected 1, found 0. | |
| *: String *--- | |
| > 0: --- foo (String) | |
| 1: --- 0 (int) | |
| ''', | |
| ); | |
| // Too few 2, relative base. | |
| testStack( | |
| stack: ['foo', 0], | |
| expected: [ValueKinds.String, ValueKinds.int], | |
| base: 2, | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Too few elements on stack. Expected 2, found 0. | |
| *: String *--- | |
| *: int *--- | |
| > 0: --- foo (String) | |
| 1: --- 0 (int) | |
| ''', | |
| ); | |
| // Too many 1, relative base. | |
| testStack( | |
| stack: ['foo', 0, true, 'bar'], | |
| expected: [ValueKinds.String], | |
| base: 2, | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Too many elements on stack. Expected 1, found 2. | |
| Unexpected element kind(s). | |
| 0: foo (String) | |
| 1: String *0 (int) | |
| > 2: --- true (bool) | |
| 3: --- bar (String) | |
| ''', | |
| ); | |
| // Too many 2, relative base. | |
| testStack( | |
| stack: ['foo', 0, true, 'bar', 42], | |
| expected: [ValueKinds.String, ValueKinds.int], | |
| base: 2, | |
| expectedMessage: ''' | |
| StackCheckerTester failure | |
| Too many elements on stack. Expected 2, found 3. | |
| Unexpected element kind(s). | |
| 0: foo (String) | |
| 1: String *0 (int) | |
| 2: int *true (bool) | |
| > 3: --- bar (String) | |
| 4: --- 42 (int) | |
| ''', | |
| ); | |
| } |