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

# 目的
+ 完全に私用です
+ 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ページ](https://github.com/NotFounds/GetTestcaseForAtcoder)

```csharp: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問題を使ってテストしてみます。

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

生成されたファイル

```csharp: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関数内でアドバイスを頂いた部分の修正

# 注意事項
+ エラー処理は行ってません
+ 出力との比較は文字列の完全一致です
+ コンテスト中の問題は取得できない可能性があります（認証が必要?）