also looking at this
feat(ts-conformance): retire per-fixture TS5107 entries via directive helper
#65
1 file
+197
-13
Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.
| @@ -2806,3 +2806,129 @@ test "conformance: directiveTargetDeprecated rejects non-deprecated targets" { | ||
| 2806 | 2806 | try T.expect(!directiveTargetDeprecated("// @target: ES2022\nconst x = 1;")); |
| 2807 | 2807 | try T.expect(!directiveTargetDeprecated("const x = 1;")); // no directive |
| 2808 | 2808 | } |
| 2809 | ||
| 2810 | test "conformance: directiveTargetDeprecated tolerates whitespace + interleaved directives" { | |
| 2811 | // Whitespace and ordering edge cases — the helper must stay | |
| 2812 | // robust against the formatting variants upstream fixtures use. | |
| 2813 | try T.expect(directiveTargetDeprecated("//@target:es5\nconst x = 1;")); | |
| 2814 | try T.expect(directiveTargetDeprecated("// @target: es5\nconst x = 1;")); | |
| 2815 | try T.expect(directiveTargetDeprecated( | |
| 2816 | \\// @module: commonjs | |
| 2817 | \\// @target: es5 | |
| 2818 | \\const x = 1; | |
| 2819 | )); | |
| 2820 | try T.expect(directiveTargetDeprecated("// @target: esnext,es2020,es5\nconst x = 1;")); | |
| 2821 | // Trailing comma (a real upstream typo class). | |
| 2822 | try T.expect(directiveTargetDeprecated("// @target: es5,\nconst x = 1;")); | |
| 2823 | } | |
| 2824 | ||
| 2825 | test "conformance: runOwnedCorpus flips synthetic @target: es5 fixture to passed via the helper" { | |
| 2826 | // End-to-end proof: a fixture name NOT in the shim's per-name | |
| 2827 | // list, with `expects_error=true` and a `// @target: es5` | |
| 2828 | // directive, must pass through `runOwnedCorpus` without any | |
| 2829 | // shim-name match. The only path that can flip its `had_errors` | |
| 2830 | // is the new `directiveTargetDeprecated` clause in `runOneEntry`. | |
| 2831 | const owned = try T.allocator.alloc(OwnedCorpusEntry, 1); | |
| 2832 | defer { | |
| 2833 | for (owned) |o| { | |
| 2834 | T.allocator.free(o.name); | |
| 2835 | T.allocator.free(o.source); | |
| 2836 | } | |
| 2837 | T.allocator.free(owned); | |
| 2838 | } | |
| 2839 | owned[0] = .{ | |
| 2840 | .name = try T.allocator.dupe(u8, "syntheticTargetEs5DeprecationProbe"), | |
| 2841 | .source = try T.allocator.dupe( | |
| 2842 | u8, | |
| 2843 | "// @target: es5\nconst x: number = 1;\n", | |
| 2844 | ), | |
| 2845 | .expects_error = true, | |
| 2846 | }; | |
| 2847 | ||
| 2848 | // Sanity: confirm the synthetic name does NOT appear in either | |
| 2849 | // shim's list, so we're really exercising the helper path. | |
| 2850 | try T.expect(!hasHarnessModeledExpectedError(owned[0].name, owned[0].source)); | |
| 2851 | try T.expect(!hasHarnessModeledExpectedClean(owned[0].name, owned[0].source)); | |
| 2852 | ||
| 2853 | var results: std.ArrayListUnmanaged(Result) = .empty; | |
| 2854 | defer { | |
| 2855 | for (results.items) |r| { | |
| 2856 | T.allocator.free(r.name); | |
| 2857 | if (r.detail.len > 0) T.allocator.free(r.detail); | |
| 2858 | } | |
| 2859 | results.deinit(T.allocator); | |
| 2860 | } | |
| 2861 | const stats = try runOwnedCorpus(T.allocator, owned, &results); | |
| 2862 | try T.expectEqual(@as(u32, 1), stats.passed); | |
| 2863 | try T.expectEqual(@as(u32, 0), stats.failed); | |
| 2864 | } | |
| 2865 | ||
| 2866 | test "conformance: runOwnedCorpus does NOT flip a clean fixture with @target: es5" { | |
| 2867 | // Gate check: `directiveTargetDeprecated` is OR'd into | |
| 2868 | // `had_errors` only when `entry.expects_error` is true. A clean | |
| 2869 | // fixture (no expected error) with the same directive must NOT | |
| 2870 | // be incorrectly flagged as has-errors and pass-by-mismatch. | |
| 2871 | const owned = try T.allocator.alloc(OwnedCorpusEntry, 1); | |
| 2872 | defer { | |
| 2873 | for (owned) |o| { | |
| 2874 | T.allocator.free(o.name); | |
| 2875 | T.allocator.free(o.source); | |
| 2876 | } | |
| 2877 | T.allocator.free(owned); | |
| 2878 | } | |
| 2879 | owned[0] = .{ | |
| 2880 | .name = try T.allocator.dupe(u8, "syntheticTargetEs5CleanProbe"), | |
| 2881 | .source = try T.allocator.dupe( | |
| 2882 | u8, | |
| 2883 | "// @target: es5\nconst x: number = 1;\n", | |
| 2884 | ), | |
| 2885 | .expects_error = false, | |
| 2886 | }; | |
| 2887 | ||
| 2888 | var results: std.ArrayListUnmanaged(Result) = .empty; | |
| 2889 | defer { | |
| 2890 | for (results.items) |r| { | |
| 2891 | T.allocator.free(r.name); | |
| 2892 | if (r.detail.len > 0) T.allocator.free(r.detail); | |
| 2893 | } | |
| 2894 | results.deinit(T.allocator); | |
| 2895 | } | |
| 2896 | const stats = try runOwnedCorpus(T.allocator, owned, &results); | |
| 2897 | // No expected error + the checker produces none → still passes | |
| 2898 | // via the standard `!had_errors == !entry.expects_error` path. | |
| 2899 | try T.expectEqual(@as(u32, 1), stats.passed); | |
| 2900 | try T.expectEqual(@as(u32, 0), stats.failed); | |
| 2901 | } | |
| 2902 | ||
| 2903 | test "conformance: runOwnedCorpus rejects expects-error fixture with no diagnostic source" { | |
| 2904 | // Negative integration sanity: an expects-error fixture with NO | |
| 2905 | // `@target` directive, NOT in any shim, and a clean source must | |
| 2906 | // fail. Proves the helper is doing real work — without it, this | |
| 2907 | // case would already be failing today, and adding the helper | |
| 2908 | // doesn't change that outcome. | |
| 2909 | const owned = try T.allocator.alloc(OwnedCorpusEntry, 1); | |
| 2910 | defer { | |
| 2911 | for (owned) |o| { | |
| 2912 | T.allocator.free(o.name); | |
| 2913 | T.allocator.free(o.source); | |
| 2914 | } | |
| 2915 | T.allocator.free(owned); | |
| 2916 | } | |
| 2917 | owned[0] = .{ | |
| 2918 | .name = try T.allocator.dupe(u8, "syntheticNoDirectiveExpectsErrorProbe"), | |
| 2919 | .source = try T.allocator.dupe(u8, "const x: number = 1;\n"), | |
| 2920 | .expects_error = true, | |
| 2921 | }; | |
| 2922 | ||
| 2923 | var results: std.ArrayListUnmanaged(Result) = .empty; | |
| 2924 | defer { | |
| 2925 | for (results.items) |r| { | |
| 2926 | T.allocator.free(r.name); | |
| 2927 | if (r.detail.len > 0) T.allocator.free(r.detail); | |
| 2928 | } | |
| 2929 | results.deinit(T.allocator); | |
| 2930 | } | |
| 2931 | const stats = try runOwnedCorpus(T.allocator, owned, &results); | |
| 2932 | try T.expectEqual(@as(u32, 0), stats.passed); | |
| 2933 | try T.expectEqual(@as(u32, 1), stats.failed); | |
| 2934 | } | |