lib_ruby_parser_ast/error/messages/
render.rs

1use crate::error::DiagnosticMessage;
2
3impl DiagnosticMessage {
4    /// Renders DiagnosticMessage by interpolating all dynamic values into a template
5    pub fn render(&self) -> String {
6        // Lexer errors
7
8        match self {
9            Self::FractionAfterNumeric {} => {
10                "unexpected fraction part after numeric literal".to_string()
11            }
12
13            Self::NoDigitsAfterDot {} => {
14                "no .<digit> floating literal anymore; put 0 before dot".to_string()
15            }
16
17            Self::UnknownTypeOfPercentString {} => {
18                "unknown type of %string".to_string()
19            }
20
21            Self::NumericLiteralWithoutDigits {} => {
22                "numeric literal without digits".to_string()
23            }
24
25            Self::UnterminatedList {} => {
26                "unterminated list meets end of file".to_string()
27            }
28
29            Self::UnterminatedRegexp {} => {
30                "unterminated regexp meets end of file".to_string()
31            }
32
33            Self::UnterminatedString {} => {
34                "unterminated string meets end of file".to_string()
35            }
36
37            Self::UnterminatedQuotedString {} => {
38                "unterminated quoted string meets end of file".to_string()
39            }
40
41            Self::InvalidUnicodeEscape {} => {
42                "invalid Unicode escape".to_string()
43            }
44
45            Self::TooLargeUnicodeCodepoint {} => {
46                "invalid Unicode codepoint (too large)".to_string()
47            }
48
49            Self::InvalidUnicodeCodepoint {} => {
50                "invalid Unicode codepoint".to_string()
51            }
52
53            Self::MultipleCodepointAtSingleChar {} => {
54                "Multiple codepoints at single character literal".to_string()
55            }
56
57            Self::InvalidEscapeCharacter {} => {
58                "Invalid escape character syntax".to_string()
59            }
60
61            Self::InvalidHexEscape {} => {
62                "invalid hex escape".to_string()
63            }
64
65            Self::UnterminatedHeredoc { heredoc_id } => {
66                format!("can't find string \"{}\" anywhere before EOF", heredoc_id)
67            }
68
69            Self::UnterminatedHeredocId {} => {
70                "unterminated here document identifier".to_string()
71            }
72
73            Self::SlashRAtMiddleOfLine {} => {
74                "encountered \\r in middle of line, treated as a mere space".to_string()
75            }
76
77            Self::DStarInterpretedAsArgPrefix {} => {
78                "`**' interpreted as argument prefix".to_string()
79            }
80
81            Self::StarInterpretedAsArgPrefix {} => {
82                "`*' interpreted as argument prefix".to_string()
83            }
84
85            Self::AmpersandInterpretedAsArgPrefix {} => {
86                "`&' interpreted as argument prefix".to_string()
87            }
88
89            Self::TripleDotAtEol {} => {
90                "... at EOL, should be parenthesized?".to_string()
91            }
92
93            Self::ParenthesesIterpretedAsArglist {} => {
94                "parentheses after method name is interpreted as an argument list, not a decomposed argument"
95                    .to_string()
96            }
97
98            Self::AmbiguousFirstArgument { operator } => {
99                format!(
100                    "ambiguous first argument; put parentheses or a space even after `{}' operator",
101                    *operator as char
102                )
103            }
104
105            Self::AmbiguousOperator {
106                operator,
107                interpreted_as,
108            } => {
109                format!(
110                    "`{}' after local variable or literal is interpreted as binary operator even though it seems like {}",
111                    operator,
112                    interpreted_as,
113                )
114            }
115
116            Self::InvalidCharacterSyntax { suggestion } => {
117                format!("invalid character syntax; use {}", suggestion)
118            }
119
120            Self::InvalidOctalDigit {} => {
121                "Invalid octal digit".to_string()
122            }
123
124            Self::TrailingCharInNumber { c } => {
125                format!("trailing `{}' in number", *c as char)
126            }
127
128            Self::EmbeddedDocumentMeetsEof {} => {
129                "embedded document meets end of file".to_string()
130            }
131
132            Self::InvalidChar { c } => {
133                format!("Invalid char `{}' in expression", *c as char)
134            }
135
136            Self::IncompleteCharacterSyntax {} => {
137                "incomplete character syntax".to_string()
138            }
139
140            Self::GvarWithoutId {} => {
141                "`$' without identifiers is not allowed as a global variable name".to_string()
142            }
143
144            Self::InvalidGvarName { c } => {
145                format!("`${}' is not allowed as a global variable name", *c as char)
146            }
147
148            Self::IvarWithoutId {} => {
149                "`@' without identifiers is not allowed as an instance variable name".to_string()
150            }
151
152            Self::InvalidIvarName { c } => {
153                format!(
154                    "`@{}' is not allowed as an instance variable name",
155                    *c as char
156                )
157            }
158
159            Self::CvarWithoutId {} => {
160                "`@@' without identifiers is not allowed as a class variable name".to_string()
161            }
162
163            Self::InvalidCvarName { c } => {
164                format!("`@@{}' is not allowed as a class variable name", *c as char)
165            }
166
167            Self::UnknownRegexOptions { options } => {
168                format!("unknown regexp options - {}", options)
169            }
170
171            Self::AmbiguousTernaryOperator { condition } => {
172                format!(
173                    "`?' just followed by `{}' is interpreted as a conditional operator, put a space after `?'",
174                    condition
175                )
176            }
177
178            Self::AmbiguousRegexp {} => {
179                "ambiguity between regexp and two divisions: wrap regexp in parentheses or add a space after `/' operator"
180                        .to_string()
181            }
182
183            Self::UnterminatedUnicodeEscape {} => {
184                "unterminated Unicode escape".to_string()
185            }
186
187            Self::EncodingError { error } => {
188                format!("encoding error: {}", error)
189            }
190
191            Self::InvalidMultibyteChar {} => {
192                "invalid multibyte char (UTF-8)".to_string()
193            }
194
195            // Parser errors
196            Self::ElseWithoutRescue {} => {
197                "else without rescue is useless".to_string()
198            }
199
200            Self::BeginNotAtTopLevel {} => {
201                "BEGIN is permitted only at toplevel".to_string()
202            }
203
204            Self::AliasNthRef {} => {
205                "can't make alias for the number variables".to_string()
206            }
207
208            Self::CsendInsideMasgn {} => {
209                "&. inside multiple assignment destination".to_string()
210            }
211
212            Self::ClassOrModuleNameMustBeConstant {} => {
213                "class/module name must be CONSTANT".to_string()
214            }
215
216            Self::EndlessSetterDefinition {} => {
217                "setter method cannot be defined in an endless method definition".to_string()
218            }
219
220            Self::InvalidIdToGet { identifier } => {
221                format!("identifier {} is not valid to get", identifier)
222            }
223
224            Self::ForwardArgAfterRestarg {} => {
225                "... after rest argument".to_string()
226            }
227
228            Self::NoAnonymousBlockarg {} => {
229                "no anonymous block parameter".to_string()
230            }
231
232            Self::UnexpectedToken { token_name } => {
233                format!("unexpected {}", token_name)
234            }
235
236            Self::ClassDefinitionInMethodBody {} => {
237                "class definition in method body".to_string()
238            }
239
240            Self::ModuleDefinitionInMethodBody {} => {
241                "module definition in method body".to_string()
242            }
243
244            Self::InvalidReturnInClassOrModuleBody {} => {
245                "Invalid return in class/module body".to_string()
246            }
247
248            Self::ConstArgument {} => {
249                "formal argument cannot be a constant".to_string()
250            }
251
252            Self::IvarArgument {} => {
253                "formal argument cannot be an instance variable".to_string()
254            }
255
256            Self::GvarArgument {} => {
257                "formal argument cannot be a global variable".to_string()
258            }
259
260            Self::CvarArgument {} => {
261                "formal argument cannot be a class variable".to_string()
262            }
263
264            Self::NoSuchLocalVariable { var_name } => {
265                format!("{}: no such local variable", var_name)
266            }
267
268            Self::OrdinaryParamDefined {} => {
269                "ordinary parameter is defined".to_string()
270            }
271
272            Self::NumparamUsed {} => {
273                "numbered parameter is already used".to_string()
274            }
275
276            Self::TokAtEolWithoutExpression { token_name } => {
277                format!("`{}' at the end of line without an expression", token_name)
278            }
279
280            // Parser warnings
281            Self::EndInMethod {} => {
282                "END in method; use at_exit".to_string()
283            }
284
285            Self::ComparisonAfterComparison { comparison } => {
286                format!("comparison '{}' after comparison", comparison)
287            }
288
289            Self::DuplicateHashKey {} => {
290                "key is duplicated and overwritten".to_string()
291            }
292
293            // Builder errors
294            Self::CircularArgumentReference { arg_name } => {
295                format!("circular argument reference - {}", arg_name)
296            }
297
298            Self::DynamicConstantAssignment {} => {
299                "dynamic constant assignment".to_string()
300            }
301
302            Self::CantAssignToSelf {} => {
303                "Can't change the value of self".to_string()
304            }
305
306            Self::CantAssignToNil {} => {
307                "Can't assign to nil".to_string()
308            }
309
310            Self::CantAssignToTrue {} => {
311                "Can't assign to true".to_string()
312            }
313
314            Self::CantAssignToFalse {} => {
315                "Can't assign to false".to_string()
316            }
317
318            Self::CantAssignToFile {} => {
319                "Can't assign to __FILE__".to_string()
320            }
321
322            Self::CantAssignToLine {} => {
323                "Can't assign to __LINE__".to_string()
324            }
325
326            Self::CantAssignToEncoding {} => {
327                "Can't assign to __ENCODING__".to_string()
328            }
329
330            Self::CantAssignToNumparam { numparam } => {
331                format!("Can't assign to numbered parameter {}", numparam)
332            }
333
334            Self::CantSetVariable { var_name } => {
335                format!("Can't set variable {}", var_name)
336            }
337
338            Self::BlockGivenToYield {} => {
339                "block given to yield".to_string()
340            }
341
342            Self::BlockAndBlockArgGiven {} => {
343                "both block arg and actual block given".to_string()
344            }
345
346            Self::SymbolLiteralWithInterpolation {} => {
347                "symbol literal with interpolation is not allowed".to_string()
348            }
349
350            Self::ReservedForNumparam { numparam } => {
351                format!("{} is reserved for numbered parameter", numparam)
352            }
353
354            Self::KeyMustBeValidAsLocalVariable {} => {
355                "key must be valid as local variables".to_string()
356            }
357
358            Self::DuplicateVariableName {} => {
359                "duplicated variable name".to_string()
360            }
361
362            Self::DuplicateKeyName {} => {
363                "duplicated key name".to_string()
364            }
365
366            Self::SingletonLiteral {} => {
367                "can't define singleton method for literals".to_string()
368            }
369
370            Self::NthRefIsTooBig { nth_ref } => {
371                format!("`{}' is too big for a number variable, always nil", nth_ref)
372            }
373
374            Self::DuplicatedArgumentName {} => {
375                "duplicated argument name".to_string()
376            }
377
378            Self::RegexError { error } => {
379                error.to_string()
380            }
381
382            Self::InvalidSymbol { symbol } => {
383                format!("invalid symbol in encoding {}", symbol)
384            }
385
386            Self::VoidValueExpression {} => {
387                "void value expression".to_string()
388            }
389        }
390    }
391}
392
393#[allow(non_snake_case)]
394mod tests {
395    #[allow(unused_imports)]
396    use super::*;
397
398    #[test]
399    fn test_render_FractionAfterNumeric() {
400        assert_eq!(
401            DiagnosticMessage::FractionAfterNumeric {}.render(),
402            "unexpected fraction part after numeric literal",
403        );
404    }
405    #[test]
406    fn test_render_NoDigitsAfterDot() {
407        assert_eq!(
408            DiagnosticMessage::NoDigitsAfterDot {}.render(),
409            "no .<digit> floating literal anymore; put 0 before dot",
410        );
411    }
412    #[test]
413    fn test_render_UnknownTypeOfPercentString() {
414        assert_eq!(
415            DiagnosticMessage::UnknownTypeOfPercentString {}.render(),
416            "unknown type of %string",
417        );
418    }
419    #[test]
420    fn test_render_NumericLiteralWithoutDigits() {
421        assert_eq!(
422            DiagnosticMessage::NumericLiteralWithoutDigits {}.render(),
423            "numeric literal without digits",
424        );
425    }
426    #[test]
427    fn test_render_UnterminatedList() {
428        assert_eq!(
429            DiagnosticMessage::UnterminatedList {}.render(),
430            "unterminated list meets end of file",
431        );
432    }
433    #[test]
434    fn test_render_UnterminatedRegexp() {
435        assert_eq!(
436            DiagnosticMessage::UnterminatedRegexp {}.render(),
437            "unterminated regexp meets end of file",
438        );
439    }
440    #[test]
441    fn test_render_UnterminatedString() {
442        assert_eq!(
443            DiagnosticMessage::UnterminatedString {}.render(),
444            "unterminated string meets end of file",
445        );
446    }
447    #[test]
448    fn test_render_UnterminatedQuotedString() {
449        assert_eq!(
450            DiagnosticMessage::UnterminatedQuotedString {}.render(),
451            "unterminated quoted string meets end of file",
452        );
453    }
454    #[test]
455    fn test_render_InvalidUnicodeEscape() {
456        assert_eq!(
457            DiagnosticMessage::InvalidUnicodeEscape {}.render(),
458            "invalid Unicode escape",
459        );
460    }
461    #[test]
462    fn test_render_TooLargeUnicodeCodepoint() {
463        assert_eq!(
464            DiagnosticMessage::TooLargeUnicodeCodepoint {}.render(),
465            "invalid Unicode codepoint (too large)",
466        );
467    }
468    #[test]
469    fn test_render_InvalidUnicodeCodepoint() {
470        assert_eq!(
471            DiagnosticMessage::InvalidUnicodeCodepoint {}.render(),
472            "invalid Unicode codepoint",
473        );
474    }
475    #[test]
476    fn test_render_MultipleCodepointAtSingleChar() {
477        assert_eq!(
478            DiagnosticMessage::MultipleCodepointAtSingleChar {}.render(),
479            "Multiple codepoints at single character literal",
480        );
481    }
482    #[test]
483    fn test_render_InvalidEscapeCharacter() {
484        assert_eq!(
485            DiagnosticMessage::InvalidEscapeCharacter {}.render(),
486            "Invalid escape character syntax",
487        );
488    }
489    #[test]
490    fn test_render_InvalidHexEscape() {
491        assert_eq!(
492            DiagnosticMessage::InvalidHexEscape {}.render(),
493            "invalid hex escape",
494        );
495    }
496
497    #[test]
498    fn test_render_UnterminatedHeredoc() {
499        assert_eq!(
500            DiagnosticMessage::UnterminatedHeredoc {
501                heredoc_id: String::from("FOO")
502            }
503            .render(),
504            "can't find string \"FOO\" anywhere before EOF",
505        );
506    }
507    #[test]
508    fn test_render_UnterminatedHeredocId() {
509        assert_eq!(
510            DiagnosticMessage::UnterminatedHeredocId {}.render(),
511            "unterminated here document identifier",
512        );
513    }
514    #[test]
515    fn test_render_SlashRAtMiddleOfLine() {
516        assert_eq!(
517            DiagnosticMessage::SlashRAtMiddleOfLine {}.render(),
518            "encountered \\r in middle of line, treated as a mere space",
519        );
520    }
521    #[test]
522    fn test_render_DStarInterpretedAsArgPrefix() {
523        assert_eq!(
524            DiagnosticMessage::DStarInterpretedAsArgPrefix {}.render(),
525            "`**' interpreted as argument prefix",
526        );
527    }
528    #[test]
529    fn test_render_StarInterpretedAsArgPrefix() {
530        assert_eq!(
531            DiagnosticMessage::StarInterpretedAsArgPrefix {}.render(),
532            "`*' interpreted as argument prefix",
533        );
534    }
535    #[test]
536    fn test_render_AmpersandInterpretedAsArgPrefix() {
537        assert_eq!(
538            DiagnosticMessage::AmpersandInterpretedAsArgPrefix {}.render(),
539            "`&' interpreted as argument prefix",
540        );
541    }
542    #[test]
543    fn test_render_TripleDotAtEol() {
544        assert_eq!(
545            DiagnosticMessage::TripleDotAtEol {}.render(),
546            "... at EOL, should be parenthesized?",
547        );
548    }
549    #[test]
550    fn test_render_ParenthesesIterpretedAsArglist() {
551        assert_eq!(
552        DiagnosticMessage::ParenthesesIterpretedAsArglist {}.render(),
553        "parentheses after method name is interpreted as an argument list, not a decomposed argument",
554    );
555    }
556    #[test]
557    fn test_render_AmbiguousFirstArgument() {
558        assert_eq!(
559            DiagnosticMessage::AmbiguousFirstArgument { operator: b'+' }.render(),
560            "ambiguous first argument; put parentheses or a space even after `+' operator",
561        );
562    }
563    #[test]
564    fn test_render_AmbiguousOperator() {
565        assert_eq!(
566        DiagnosticMessage::AmbiguousOperator {
567            operator: String::from("+"),
568            interpreted_as: String::from("-")
569        }
570        .render(),
571        "`+' after local variable or literal is interpreted as binary operator even though it seems like -",
572    );
573    }
574    #[test]
575    fn test_render_InvalidCharacterSyntax() {
576        assert_eq!(
577            DiagnosticMessage::InvalidCharacterSyntax {
578                suggestion: String::from("foo")
579            }
580            .render(),
581            "invalid character syntax; use foo",
582        );
583    }
584    #[test]
585    fn test_render_InvalidOctalDigit() {
586        assert_eq!(
587            DiagnosticMessage::InvalidOctalDigit {}.render(),
588            "Invalid octal digit"
589        );
590    }
591    #[test]
592    fn test_render_TrailingCharInNumber() {
593        assert_eq!(
594            DiagnosticMessage::TrailingCharInNumber { c: b'!' }.render(),
595            "trailing `!' in number",
596        );
597    }
598    #[test]
599    fn test_render_EmbeddedDocumentMeetsEof() {
600        assert_eq!(
601            DiagnosticMessage::EmbeddedDocumentMeetsEof {}.render(),
602            "embedded document meets end of file",
603        );
604    }
605    #[test]
606    fn test_render_InvalidChar() {
607        assert_eq!(
608            DiagnosticMessage::InvalidChar { c: b'!' }.render(),
609            "Invalid char `!' in expression",
610        );
611    }
612    #[test]
613    fn test_render_IncompleteCharacterSyntax() {
614        assert_eq!(
615            DiagnosticMessage::IncompleteCharacterSyntax {}.render(),
616            "incomplete character syntax",
617        );
618    }
619    #[test]
620    fn test_render_GvarWithoutId() {
621        assert_eq!(
622            DiagnosticMessage::GvarWithoutId {}.render(),
623            "`$' without identifiers is not allowed as a global variable name",
624        );
625    }
626    #[test]
627    fn test_render_InvalidGvarName() {
628        assert_eq!(
629            DiagnosticMessage::InvalidGvarName { c: b'!' }.render(),
630            "`$!' is not allowed as a global variable name",
631        );
632    }
633    #[test]
634    fn test_render_IvarWithoutId() {
635        assert_eq!(
636            DiagnosticMessage::IvarWithoutId {}.render(),
637            "`@' without identifiers is not allowed as an instance variable name",
638        );
639    }
640    #[test]
641    fn test_render_InvalidIvarName() {
642        assert_eq!(
643            DiagnosticMessage::InvalidIvarName { c: b'!' }.render(),
644            "`@!' is not allowed as an instance variable name",
645        );
646    }
647    #[test]
648    fn test_render_CvarWithoutId() {
649        assert_eq!(
650            DiagnosticMessage::CvarWithoutId {}.render(),
651            "`@@' without identifiers is not allowed as a class variable name",
652        );
653    }
654    #[test]
655    fn test_render_InvalidCvarName() {
656        assert_eq!(
657            DiagnosticMessage::InvalidCvarName { c: b'!' }.render(),
658            "`@@!' is not allowed as a class variable name",
659        );
660    }
661    #[test]
662    fn test_render_UnknownRegexOptions() {
663        assert_eq!(
664            DiagnosticMessage::UnknownRegexOptions {
665                options: String::from("foo")
666            }
667            .render(),
668            "unknown regexp options - foo",
669        );
670    }
671    #[test]
672    fn test_render_AmbiguousTernaryOperator() {
673        assert_eq!(
674            DiagnosticMessage::AmbiguousTernaryOperator {
675                condition: String::from("foo")
676            }
677            .render(),
678            "`?' just followed by `foo' is interpreted as a conditional operator, put a space after `?'",
679        );
680    }
681    #[test]
682    fn test_render_AmbiguousRegexp() {
683        assert_eq!(DiagnosticMessage::AmbiguousRegexp {}.render(), "ambiguity between regexp and two divisions: wrap regexp in parentheses or add a space after `/' operator",);
684    }
685    #[test]
686    fn test_render_UnterminatedUnicodeEscape() {
687        assert_eq!(
688            DiagnosticMessage::UnterminatedUnicodeEscape {}.render(),
689            "unterminated Unicode escape",
690        );
691    }
692    #[test]
693    fn test_render_EncodingError() {
694        assert_eq!(
695            DiagnosticMessage::EncodingError {
696                error: String::from("foo")
697            }
698            .render(),
699            "encoding error: foo",
700        );
701    }
702    #[test]
703    fn test_render_InvalidMultibyteChar() {
704        assert_eq!(
705            DiagnosticMessage::InvalidMultibyteChar {}.render(),
706            "invalid multibyte char (UTF-8)",
707        );
708    }
709    #[test]
710    fn test_render_ElseWithoutRescue() {
711        assert_eq!(
712            DiagnosticMessage::ElseWithoutRescue {}.render(),
713            "else without rescue is useless",
714        );
715    }
716    #[test]
717    fn test_render_BeginNotAtTopLevel() {
718        assert_eq!(
719            DiagnosticMessage::BeginNotAtTopLevel {}.render(),
720            "BEGIN is permitted only at toplevel",
721        );
722    }
723    #[test]
724    fn test_render_AliasNthRef() {
725        assert_eq!(
726            DiagnosticMessage::AliasNthRef {}.render(),
727            "can't make alias for the number variables",
728        );
729    }
730    #[test]
731    fn test_render_CsendInsideMasgn() {
732        assert_eq!(
733            DiagnosticMessage::CsendInsideMasgn {}.render(),
734            "&. inside multiple assignment destination",
735        );
736    }
737    #[test]
738    fn test_render_ClassOrModuleNameMustBeConstant() {
739        assert_eq!(
740            DiagnosticMessage::ClassOrModuleNameMustBeConstant {}.render(),
741            "class/module name must be CONSTANT",
742        );
743    }
744    #[test]
745    fn test_render_EndlessSetterDefinition() {
746        assert_eq!(
747            DiagnosticMessage::EndlessSetterDefinition {}.render(),
748            "setter method cannot be defined in an endless method definition",
749        );
750    }
751    #[test]
752    fn test_render_InvalidIdToGet() {
753        assert_eq!(
754            DiagnosticMessage::InvalidIdToGet {
755                identifier: String::from("foo")
756            }
757            .render(),
758            "identifier foo is not valid to get",
759        );
760    }
761    #[test]
762    fn test_render_ForwardArgAfterRestarg() {
763        assert_eq!(
764            DiagnosticMessage::ForwardArgAfterRestarg {}.render(),
765            "... after rest argument",
766        );
767    }
768    #[test]
769    fn test_render_NoAnonymousBlockarg() {
770        assert_eq!(
771            DiagnosticMessage::NoAnonymousBlockarg {}.render(),
772            "no anonymous block parameter",
773        );
774    }
775    #[test]
776    fn test_render_UnexpectedToken() {
777        assert_eq!(
778            DiagnosticMessage::UnexpectedToken {
779                token_name: String::from("tUNKNOWN")
780            }
781            .render(),
782            "unexpected tUNKNOWN",
783        );
784    }
785    #[test]
786    fn test_render_ClassDefinitionInMethodBody() {
787        assert_eq!(
788            DiagnosticMessage::ClassDefinitionInMethodBody {}.render(),
789            "class definition in method body",
790        );
791    }
792    #[test]
793    fn test_render_ModuleDefinitionInMethodBody() {
794        assert_eq!(
795            DiagnosticMessage::ModuleDefinitionInMethodBody {}.render(),
796            "module definition in method body",
797        );
798    }
799    #[test]
800    fn test_render_InvalidReturnInClassOrModuleBody() {
801        assert_eq!(
802            DiagnosticMessage::InvalidReturnInClassOrModuleBody {}.render(),
803            "Invalid return in class/module body",
804        );
805    }
806    #[test]
807    fn test_render_ConstArgument() {
808        assert_eq!(
809            DiagnosticMessage::ConstArgument {}.render(),
810            "formal argument cannot be a constant",
811        );
812    }
813    #[test]
814    fn test_render_IvarArgument() {
815        assert_eq!(
816            DiagnosticMessage::IvarArgument {}.render(),
817            "formal argument cannot be an instance variable",
818        );
819    }
820    #[test]
821    fn test_render_GvarArgument() {
822        assert_eq!(
823            DiagnosticMessage::GvarArgument {}.render(),
824            "formal argument cannot be a global variable",
825        );
826    }
827    #[test]
828    fn test_render_CvarArgument() {
829        assert_eq!(
830            DiagnosticMessage::CvarArgument {}.render(),
831            "formal argument cannot be a class variable",
832        );
833    }
834    #[test]
835    fn test_render_NoSuchLocalVariable() {
836        assert_eq!(
837            DiagnosticMessage::NoSuchLocalVariable {
838                var_name: String::from("foo")
839            }
840            .render(),
841            "foo: no such local variable",
842        );
843    }
844    #[test]
845    fn test_render_OrdinaryParamDefined() {
846        assert_eq!(
847            DiagnosticMessage::OrdinaryParamDefined {}.render(),
848            "ordinary parameter is defined",
849        );
850    }
851    #[test]
852    fn test_render_NumparamUsed() {
853        assert_eq!(
854            DiagnosticMessage::NumparamUsed {}.render(),
855            "numbered parameter is already used",
856        );
857    }
858    #[test]
859    fn test_render_TokAtEolWithoutExpression() {
860        assert_eq!(
861            DiagnosticMessage::TokAtEolWithoutExpression {
862                token_name: String::from("tTOKEN")
863            }
864            .render(),
865            "`tTOKEN' at the end of line without an expression",
866        );
867    }
868    #[test]
869    fn test_render_EndInMethod() {
870        assert_eq!(
871            DiagnosticMessage::EndInMethod {}.render(),
872            String::from("END in method; use at_exit"),
873        );
874    }
875    #[test]
876    fn test_render_ComparisonAfterComparison() {
877        assert_eq!(
878            DiagnosticMessage::ComparisonAfterComparison {
879                comparison: String::from("<=>")
880            }
881            .render(),
882            "comparison '<=>' after comparison",
883        );
884    }
885    #[test]
886    fn test_render_DuplicateHashKey() {
887        assert_eq!(
888            DiagnosticMessage::DuplicateHashKey {}.render(),
889            "key is duplicated and overwritten",
890        );
891    }
892    #[test]
893    fn test_render_CircularArgumentReference() {
894        assert_eq!(
895            DiagnosticMessage::CircularArgumentReference {
896                arg_name: String::from("foo")
897            }
898            .render(),
899            "circular argument reference - foo",
900        );
901    }
902    #[test]
903    fn test_render_DynamicConstantAssignment() {
904        assert_eq!(
905            DiagnosticMessage::DynamicConstantAssignment {}.render(),
906            "dynamic constant assignment",
907        );
908    }
909    #[test]
910    fn test_render_CantAssignToSelf() {
911        assert_eq!(
912            DiagnosticMessage::CantAssignToSelf {}.render(),
913            "Can't change the value of self",
914        );
915    }
916    #[test]
917    fn test_render_CantAssignToNil() {
918        assert_eq!(
919            DiagnosticMessage::CantAssignToNil {}.render(),
920            "Can't assign to nil",
921        );
922    }
923    #[test]
924    fn test_render_CantAssignToTrue() {
925        assert_eq!(
926            DiagnosticMessage::CantAssignToTrue {}.render(),
927            "Can't assign to true",
928        );
929    }
930    #[test]
931    fn test_render_CantAssignToFalse() {
932        assert_eq!(
933            DiagnosticMessage::CantAssignToFalse {}.render(),
934            "Can't assign to false",
935        );
936    }
937    #[test]
938    fn test_render_CantAssignToFile() {
939        assert_eq!(
940            DiagnosticMessage::CantAssignToFile {}.render(),
941            "Can't assign to __FILE__",
942        );
943    }
944    #[test]
945    fn test_render_CantAssignToLine() {
946        assert_eq!(
947            DiagnosticMessage::CantAssignToLine {}.render(),
948            "Can't assign to __LINE__",
949        );
950    }
951    #[test]
952    fn test_render_CantAssignToEncoding() {
953        assert_eq!(
954            DiagnosticMessage::CantAssignToEncoding {}.render(),
955            "Can't assign to __ENCODING__",
956        );
957    }
958    #[test]
959    fn test_render_CantAssignToNumparam() {
960        assert_eq!(
961            DiagnosticMessage::CantAssignToNumparam {
962                numparam: String::from("_42")
963            }
964            .render(),
965            "Can't assign to numbered parameter _42",
966        );
967    }
968    #[test]
969    fn test_render_CantSetVariable() {
970        assert_eq!(
971            DiagnosticMessage::CantSetVariable {
972                var_name: String::from("foo")
973            }
974            .render(),
975            "Can't set variable foo",
976        );
977    }
978    #[test]
979    fn test_render_BlockGivenToYield() {
980        assert_eq!(
981            DiagnosticMessage::BlockGivenToYield {}.render(),
982            "block given to yield",
983        );
984    }
985    #[test]
986    fn test_render_BlockAndBlockArgGiven() {
987        assert_eq!(
988            DiagnosticMessage::BlockAndBlockArgGiven {}.render(),
989            "both block arg and actual block given",
990        );
991    }
992    #[test]
993    fn test_render_SymbolLiteralWithInterpolation() {
994        assert_eq!(
995            DiagnosticMessage::SymbolLiteralWithInterpolation {}.render(),
996            "symbol literal with interpolation is not allowed",
997        );
998    }
999    #[test]
1000    fn test_render_ReservedForNumparam() {
1001        assert_eq!(
1002            DiagnosticMessage::ReservedForNumparam {
1003                numparam: String::from("_42")
1004            }
1005            .render(),
1006            "_42 is reserved for numbered parameter",
1007        );
1008    }
1009    #[test]
1010    fn test_render_KeyMustBeValidAsLocalVariable() {
1011        assert_eq!(
1012            DiagnosticMessage::KeyMustBeValidAsLocalVariable {}.render(),
1013            "key must be valid as local variables",
1014        );
1015    }
1016    #[test]
1017    fn test_render_DuplicateVariableName() {
1018        assert_eq!(
1019            DiagnosticMessage::DuplicateVariableName {}.render(),
1020            "duplicated variable name",
1021        );
1022    }
1023    #[test]
1024    fn test_render_DuplicateKeyName() {
1025        assert_eq!(
1026            DiagnosticMessage::DuplicateKeyName {}.render(),
1027            "duplicated key name",
1028        );
1029    }
1030    #[test]
1031    fn test_render_SingletonLiteral() {
1032        assert_eq!(
1033            DiagnosticMessage::SingletonLiteral {}.render(),
1034            "can't define singleton method for literals",
1035        );
1036    }
1037    #[test]
1038    fn test_render_NthRefIsTooBig() {
1039        assert_eq!(
1040            DiagnosticMessage::NthRefIsTooBig {
1041                nth_ref: String::from("42")
1042            }
1043            .render(),
1044            "`42' is too big for a number variable, always nil",
1045        );
1046    }
1047    #[test]
1048    fn test_render_DuplicatedArgumentName() {
1049        assert_eq!(
1050            DiagnosticMessage::DuplicatedArgumentName {}.render(),
1051            "duplicated argument name",
1052        );
1053    }
1054    #[test]
1055    fn test_render_RegexError() {
1056        assert_eq!(
1057            DiagnosticMessage::RegexError {
1058                error: String::from("foo")
1059            }
1060            .render(),
1061            "foo",
1062        );
1063    }
1064    #[test]
1065    fn test_render_InvalidSymbol() {
1066        assert_eq!(
1067            DiagnosticMessage::InvalidSymbol {
1068                symbol: String::from("foo")
1069            }
1070            .render(),
1071            "invalid symbol in encoding foo",
1072        );
1073    }
1074    #[test]
1075    fn test_render_VoidValueExpression() {
1076        assert_eq!(
1077            DiagnosticMessage::VoidValueExpression {}.render(),
1078            "void value expression",
1079        );
1080    }
1081}