LoginSignup
5
10

More than 5 years have passed since last update.

Atcoderのテストケース例を取得し、C#のテストコード(MSTest)に変換するプログラム

Last updated at Posted at 2015-11-24

目的

  • 完全に私用です
  • C#の勉強も兼ねて作りました
  • あと、Qiitaに何か投稿してみたかった!(これが一番大きい)

言語

  • C#6.0 で書いてます

使い方

  1. Visual Stdio 2015であらかじめ、Atcoderというコンソールプロジェクトを作成し、右クリックで"単体テストの作成"をしておく
  2. 次にVisual Studio 2015で新しいC#のコンソールプロジェクトを作成し、以下のコード(Program.cs)を貼り付けて実行
  3. "Input Atcoder Problem URL : "が出てきたら、問題ページのURLを入力
  4. 実行ファイルがあるディレクトリに、"ProgramTests.cs"というファイルが作成されたら多分成功
  5. Atcoderプロジェクトの"PrgmramTests.cs"に4で作成されたファイルをコピーして終わり
    (Atcoderプロジェクトの"ProgramTests.cs"があるフォルダで、テストケース取得プログラムを起動すれば5の動作が省けて楽です)

ソースコード

Githubページ

Program.cs
using System.Text;
using System.Net;
using System.Text.RegularExpressions;
using static System.Console;
using System.IO;

namespace getTestcaseForAtcoder
{
    class Program
    {
        static void Main(string[] args)
        {
            WriteLine("Input Atcoder Problem URL : ");
            string testcases = getTestCase(getContext(ReadLine().Trim(new char[]{'\r', '\n', ' '})));

            using (StreamWriter sw = new StreamWriter("ProgramTests.cs"))
            {
                sw.Write(testcases);
            }

            WriteLine("Output to \"ProgramTests.cs\"");
        }

        static string getTestCase(string html)
        {
            string source1 = 
@"using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;

namespace Atcoder.Tests
{
    [TestClass()]
    public class ProgramTests
    {
        (TESTCASES)
        private void AssertIO(string input, string output)
        {
            StringReader reader = new StringReader(input);
            Console.SetIn(reader);

            StringWriter writer = new StringWriter();
            Console.SetOut(writer);

            Program.Main(new string[0]);

            Assert.AreEqual(output + Environment.NewLine, writer.ToString());
        }
    }
}";

            string source2 = @"
        [TestMethod()]
        [Timeout(2000)]
        public void Test(TESTNUM)()
        {
            string input  = ""(TESTCASE1)"";
            string output = ""(TESTCASE2)"";

            AssertIO(input, output);
        }";

            string anchor = "(<pre class=\"prettyprint linenums\">|<pre>)(?<testcase>.*?)</pre>";
            Regex re = new Regex(anchor, RegexOptions.IgnoreCase | RegexOptions.Singleline);

            StringBuilder sb = new StringBuilder();
            int i = 1;
            for (Match m = re.Match(html); m.Success; m = m.NextMatch())
            {
                if (m.Groups["testcase"].Value.Contains("<var>")) continue;

                string testCase1 = m.Groups["testcase"].Value; m = m.NextMatch();
                string testCase2 = m.Groups["testcase"].Value;

                testCase1 = testCase1.TrimStart('\r').TrimStart('\n').Replace("\r", "").Replace("\n", "\\n");
                testCase2 = testCase2.TrimStart('\r').TrimStart('\n').TrimEnd('\n').TrimEnd('\r').Replace("\r", "").Replace("\n", "\\n");

                sb.AppendLine(source2.Replace("(TESTNUM)", (i++).ToString()).Replace("(TESTCASE1)", testCase1).Replace("(TESTCASE2)", testCase2));
            }

            return  source1.Replace("(TESTCASES)", sb.ToString());
        }

        static string getContext(string url)
        {
            WebClient wc  = new WebClient();
            byte[]    data = wc.DownloadData(url);
            Encoding  enc = Encoding.GetEncoding("utf-8");
            string    ret = enc.GetString(data);
            wc.Dispose();
            return ret;
        }
    }
}

使用例

ABC001コンテストのA問題を使ってテストしてみます。

実行例
Input Atcoder Problem URL : 
http://abc001.contest.atcoder.jp/tasks/abc001_1
Output to \"ProgramTests.cs\"

生成されたファイル

ProgramTests.cs
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;

namespace Atcoder.Tests
{
    [TestClass()]
    public class ProgramTests
    {
        [TestMethod()]
        [Timeout(2000)]
        public void Test1()
        {
            string input = "15\n10\n";
            string output = "5";

            AssertIO(input, output);
        }

        [TestMethod()]
        [Timeout(2000)]
        public void Test2()
        {
            string input = "0\n0\n";
            string output = "0";

            AssertIO(input, output);
        }

        [TestMethod()]
        [Timeout(2000)]
        public void Test3()
        {
            string input = "5\n20\n";
            string output = "-15";

            AssertIO(input, output);
        }

        private void AssertIO(string input, string output)
        {
            StringReader reader = new StringReader(input);
            Console.SetIn(reader);

            StringWriter writer = new StringWriter();
            Console.SetOut(writer);

            Program.Main(new string[0]);

            Assert.AreEqual(output + Environment.NewLine, writer.ToString());
        }
    }
}

まとめ

  • 入出力のテストが楽になりました

変更履歴

  • 2015/11/24 公開
  • 2015/11/24 コードの訂正
  • 2015/11/25 getTestCase関数内でアドバイスを頂いた部分の修正

注意事項

  • エラー処理は行ってません
  • 出力との比較は文字列の完全一致です
  • コンテスト中の問題は取得できない可能性があります(認証が必要?)
5
10
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
10