Add Elixir tests

Add Elixir tests

# Copyright (C) 2002-2016 ProcessOne, SARL. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

defmodule FastXMLTest do
  use ExUnit.Case

  # TODO: we should be able to pass :use_maps option to :fxml_stream.parse_element/2

  test "Stream parser can return Elixir structs" do
    s1 = :fxml_stream.new(self, :infinity, [:no_gen_server, :use_maps])
    s2 = :fxml_stream.parse(s1, "<root>")
    assert receive_stanza == %FastXML.StreamStart{name: "root"}
    s3 = :fxml_stream.parse(s2, "<xmlelement>content cdata</xmlelement>")
    assert receive_stanza == %FastXML.El{name: "xmlelement", children: ["content cdata"]}
    s4 = :fxml_stream.parse(s3, "<xmlelement><empty/><subelement attribute='true'>content cdata</subelement></xmlelement>")
    assert receive_stanza == %FastXML.El{name: "xmlelement", children: ["content cdata"]}
    s5 = :fxml_stream.parse(s4, "</root>")
    assert receive_stanza == %FastXML.StreamEnd{name: "root"}
    :fxml_stream.close(s5)
  end

  test "Size of parsed stanza can be limited" do
    :todo
  end

  # TODO This test is failing at the moment
#  test "Stream parser can support arbitrary root element attributes" do
#    s1 = :fxml_stream.new(self, :infinity, [:no_gen_server, :use_maps])
#    s2 = :fxml_stream.parse(s1, "<root xmlns='myns'>")
#    assert receive_result == %FastXML.StreamStart{name: "root", attrs: %{"xmlns": "myns"}}
#    :fxml_stream.close(s2)
#  end

# TODO to test, unbound prefix error:
#     code: receive_result == %FastXML.StreamStart{name: "stream:stream", attrs: %{xmlns: "jabber:client"}}
#     lhs:  %{__struct__: FastXML.StreamError, desc: {27, "unbound prefix"}}
#     rhs:  %FastXML.StreamStart{attrs: %{xmlns: "jabber:client"}, name: "stream:stream"}

# TODO test mismatched tags

  defp receive_stanza do
    receive do
      result ->
        result
    after 2000 ->
        nil
    end
  end
end

defmodule FastXMLTest do
  use ExUnit.Case

  # TODO: we should be able to pass :use_maps option to :fxml_stream.parse_element/2

  test "Stream parser can return Elixir structs" do
    s1 = :fxml_stream.new(self, :infinity, [:no_gen_server, :use_maps])
    s2 = :fxml_stream.parse(s1, "<root>")
    assert receive_result == %FastXML.StreamStart{name: "root"}
    s3 = :fxml_stream.parse(s2, "<xmlelement>content cdata</xmlelement>")
    assert receive_result == %FastXML.El{name: "xmlelement", children: ["content cdata"]}
    s4 = :fxml_stream.parse(s3, "</root>")
    assert receive_result == %FastXML.StreamEnd{name: "root"}
    :fxml_stream.close(s4)
  end

  # TODO This test is failing at the moment
#  test "Stream parser can support arbitrary root element attributes" do
#    s1 = :fxml_stream.new(self, :infinity, [:no_gen_server, :use_maps])
#    s2 = :fxml_stream.parse(s1, "<root xmlns='myns'>")
#    assert receive_result == %FastXML.StreamStart{name: "root", attrs: %{"xmlns": "myns"}}
#    :fxml_stream.close(s2)
#  end

# TODO to test, unbound prefix error:
#     code: receive_result == %FastXML.StreamStart{name: "stream:stream", attrs: %{xmlns: "jabber:client"}}
#     lhs:  %{__struct__: FastXML.StreamError, desc: {27, "unbound prefix"}}
#     rhs:  %FastXML.StreamStart{attrs: %{xmlns: "jabber:client"}, name: "stream:stream"}

  defp receive_result do
    receive do
      result ->
        result
    after 2000 ->
        nil
    end
  end
end


Test implicit module generation on protocols.

defmodule ProtocolTest do
  use ExUnit::Case

  defmodule __MODULE__ :: WithAll do
    defprotocol [blank(thing)]
  end

  defmodule __MODULE__ :: WithExcept do
    defprotocol [blank(thing)], except: [Atom, Number, List]
  end

  defprotocol WithOnly, [blank(thing)], only: [Tuple, Function]

  defrecord Foo, a: 0, b: 0

  defimpl __MODULE__ :: WithAll, for: Foo do
    def blank(record) do
      record.a + record.b == 0
    end
  end

  def test_protocol_with_all do
    assert_undef(ProtocolTest::WithAll, Atom, :foo)
    assert_undef(ProtocolTest::WithAll, Function, fn(x, do: x))
    assert_undef(ProtocolTest::WithAll, Number, 1)
    assert_undef(ProtocolTest::WithAll, Number, 1.1)
    assert_undef(ProtocolTest::WithAll, List, [])
    assert_undef(ProtocolTest::WithAll, List, [1,2,3])
    assert_undef(ProtocolTest::WithAll, Tuple, {})
    assert_undef(ProtocolTest::WithAll, Tuple, {1,2,3})
    assert_undef(ProtocolTest::WithAll, Tuple, {Bar,2,3})
    assert_undef(ProtocolTest::WithAll, BitString, "foo")
    assert_undef(ProtocolTest::WithAll, BitString, bitstr(1))
    assert_undef(ProtocolTest::WithAll, PID, self())
    assert_undef(ProtocolTest::WithAll, Port, hd(:erlang.ports))
    assert_undef(ProtocolTest::WithAll, Reference, make_ref)
  end

  def test_protocol_with_except do
    assert_undef(ProtocolTest::WithExcept, Any, :foo)
    assert_undef(ProtocolTest::WithExcept, Any, 1)
    assert_undef(ProtocolTest::WithExcept, Any, [1,2,3])
    assert_undef(ProtocolTest::WithExcept, Function, fn(x, do: x))
    assert_undef(ProtocolTest::WithExcept, Tuple, {})
  end

  def test_protocol_with_only do
    assert_undef(ProtocolTest::WithOnly, Any, :foo)
    assert_undef(ProtocolTest::WithOnly, Any, 1)
    assert_undef(ProtocolTest::WithOnly, Any, [1,2,3])
    assert_undef(ProtocolTest::WithOnly, Function, fn(x, do: x))
    assert_undef(ProtocolTest::WithOnly, Tuple, {})
  end

  def test_protocol_with_record do
    true  = ProtocolTest::WithAll.blank(ProtocolTest::Foo.new)
    false = ProtocolTest::WithAll.blank(ProtocolTest::Foo.new(a: 1))
  end

  # Dispatch `blank(thing)` to the given `target`
  # and check if it will dispatch (and successfully fail)
  # to the proper implementation `impl`.
  defp assert_undef(target, impl, thing) do
    try do
      target.blank(thing)
      error("Expected invocation to fail")
    catch: { :error, :undef, [stack|_] }
      ref = target :: impl
      if hd(stack) == { ref, :blank, [thing] } do
        :ok
      elsif: hd(stack) == { ref, :blank, [thing], []}
        :ok
      else:
        error("Invalid stack #{stack}")
      end
    end
  end
end

defmodule ProtocolTest do
  use ExUnit::Case

  defmodule __MODULE__ :: WithAll do
    defprotocol [blank(thing)]
  end

  defmodule __MODULE__ :: WithExcept do
    defprotocol [blank(thing)], except: [Atom, Number, List]
  end

  defmodule __MODULE__ :: WithOnly do
    defprotocol [blank(thing)], only: [Tuple, Function]
  end

  defrecord Foo, a: 0, b: 0

  defimpl __MODULE__ :: WithAll, for: Foo do
    def blank(record) do
      record.a + record.b == 0
    end
  end

  def test_protocol_with_all do
    assert_undef(ProtocolTest::WithAll, Atom, :foo)
    assert_undef(ProtocolTest::WithAll, Function, fn(x, do: x))
    assert_undef(ProtocolTest::WithAll, Number, 1)
    assert_undef(ProtocolTest::WithAll, Number, 1.1)
    assert_undef(ProtocolTest::WithAll, List, [])
    assert_undef(ProtocolTest::WithAll, List, [1,2,3])
    assert_undef(ProtocolTest::WithAll, Tuple, {})
    assert_undef(ProtocolTest::WithAll, Tuple, {1,2,3})
    assert_undef(ProtocolTest::WithAll, Tuple, {Bar,2,3})
    assert_undef(ProtocolTest::WithAll, BitString, "foo")
    assert_undef(ProtocolTest::WithAll, BitString, bitstr(1))
    assert_undef(ProtocolTest::WithAll, PID, self())
    assert_undef(ProtocolTest::WithAll, Port, hd(:erlang.ports))
    assert_undef(ProtocolTest::WithAll, Reference, make_ref)
  end

  def test_protocol_with_except do
    assert_undef(ProtocolTest::WithExcept, Any, :foo)
    assert_undef(ProtocolTest::WithExcept, Any, 1)
    assert_undef(ProtocolTest::WithExcept, Any, [1,2,3])
    assert_undef(ProtocolTest::WithExcept, Function, fn(x, do: x))
    assert_undef(ProtocolTest::WithExcept, Tuple, {})
  end

  def test_protocol_with_only do
    assert_undef(ProtocolTest::WithOnly, Any, :foo)
    assert_undef(ProtocolTest::WithOnly, Any, 1)
    assert_undef(ProtocolTest::WithOnly, Any, [1,2,3])
    assert_undef(ProtocolTest::WithOnly, Function, fn(x, do: x))
    assert_undef(ProtocolTest::WithOnly, Tuple, {})
  end

  def test_protocol_with_record do
    true  = ProtocolTest::WithAll.blank(ProtocolTest::Foo.new)
    false = ProtocolTest::WithAll.blank(ProtocolTest::Foo.new(a: 1))
  end

  # Dispatch `blank(thing)` to the given `target`
  # and check if it will dispatch (and successfully fail)
  # to the proper implementation `impl`.
  defp assert_undef(target, impl, thing) do
    try do
      target.blank(thing)
      error("Expected invocation to fail")
    catch: { :error, :undef, [stack|_] }
      ref = target :: impl
      if hd(stack) == { ref, :blank, [thing] } do
        :ok
      elsif: hd(stack) == { ref, :blank, [thing], []}
        :ok
      else:
        error("Invalid stack #{stack}")
      end
    end
  end
end


Empty is invalid too

Empty is invalid too

defmodule Iodized.FeatureTest do
  defmodule AllTest do
    use ExUnit.Case, async: true

    setup do
      {:ok, [
          dummy_state: (HashDict.new |> HashDict.put("WA", "Perth")),

          always_on_feature: %Iodized.Feature{
            id: 1,
            title: "always on feature",
            description: "Does stuff",
            master_switch_state: "on",
            definition: nil
          },

          always_off_feature: %Iodized.Feature{
            id: 2,
            title: "always off feature",
            description: "Does nothing",
            master_switch_state: "off",
            definition: nil
          },

          useful_feature: %Iodized.Feature{
            id: 3,
            title: "Pete's Feature",
            description: "Does stuff",
            master_switch_state: "dynamic",
            definition: %Iodized.Definition.All{definitions: [
                %Iodized.Definition.Is{actual_state_param_name: "username", allowed_value: "paj"}
              ]
            }
          },

          serialized_feature: %{
            id: 3,
            title: "Pete's Feature",
            description: "Does stuff",
            master_switch_state: "dynamic",
            definition: %{
              operand: "all",
              definitions: [
                %{
                  operand: "is", param_name: "username", value: "paj"
                }
              ]
            }
          }
        ]
      }
    end

    test "do?/2 returns a tuple {:ok, boolean}", context do
      result = Iodized.Feature.do?(context[:always_on_feature], nil)
      assert is_tuple(result)
      assert elem(result, 0) === :ok
      assert elem(result, 1) |> is_boolean
    end

    test "serialization", context do
      feature = context[:useful_feature]
      serialized_feature = context[:serialized_feature]

      assert(Iodized.Feature.json(feature) === serialized_feature)
    end

    test "deserialization", context do
      feature = context[:useful_feature]
      serialized_feature = context[:serialized_feature]

      assert(Iodized.Feature.from_json(serialized_feature) == feature)
    end

    test "do?/2 is false when no state is sent and master_switch_state is nil", context do
      feature = context[:useful_feature]
      state = context[:dummy_state]
      {:ok, result} = Iodized.Feature.do?(feature, state)
      refute(result)
    end

    test "do?/2 is true when master_switch_state is true", context do
      feature = context[:always_on_feature]
      state = context[:dummy_state]
      {:ok, result} = Iodized.Feature.do?(feature, state)
      assert(result)
    end

    test "do?/2 is true when master_switch_state is false", context do
      feature = context[:always_off_feature]
      state = context[:dummy_state]
      {:ok, result} = Iodized.Feature.do?(feature, state)
      refute(result)
    end

    test "do/?2 is true when the logic says so", context do
      feature = context[:useful_feature]
      state = HashDict.new |> HashDict.put("username", "paj")
      {:ok, result} = Iodized.Feature.do?(feature, state)
      assert(result)
    end

    test "do/?2 is false when the logic says so", context do
      feature = context[:useful_feature]
      state = HashDict.new |> HashDict.put("username", "madlep")
      {:ok, result} = Iodized.Feature.do?(feature, state)
      refute(result)
    end

    test "valid_title?/2 is true when lowercase alphanumeric with underscores or dashes" do
      assert Iodized.Feature.valid_title?("abc123_valid-title")
    end

    test "valid_title?/2 is false when an invalid character is in the title" do
      refute Iodized.Feature.valid_title?("abc123 invalid-title")
      refute Iodized.Feature.valid_title?("XYZ")
      refute Iodized.Feature.valid_title?("")
    end
  end
end

defmodule Iodized.FeatureTest do
  defmodule AllTest do
    use ExUnit.Case, async: true

    setup do
      {:ok, [
          dummy_state: (HashDict.new |> HashDict.put("WA", "Perth")),

          always_on_feature: %Iodized.Feature{
            id: 1,
            title: "always on feature",
            description: "Does stuff",
            master_switch_state: "on",
            definition: nil
          },

          always_off_feature: %Iodized.Feature{
            id: 2,
            title: "always off feature",
            description: "Does nothing",
            master_switch_state: "off",
            definition: nil
          },

          useful_feature: %Iodized.Feature{
            id: 3,
            title: "Pete's Feature",
            description: "Does stuff",
            master_switch_state: "dynamic",
            definition: %Iodized.Definition.All{definitions: [
                %Iodized.Definition.Is{actual_state_param_name: "username", allowed_value: "paj"}
              ]
            }
          },

          serialized_feature: %{
            id: 3,
            title: "Pete's Feature",
            description: "Does stuff",
            master_switch_state: "dynamic",
            definition: %{
              operand: "all",
              definitions: [
                %{
                  operand: "is", param_name: "username", value: "paj"
                }
              ]
            }
          }
        ]
      }
    end

    test "do?/2 returns a tuple {:ok, boolean}", context do
      result = Iodized.Feature.do?(context[:always_on_feature], nil)
      assert is_tuple(result)
      assert elem(result, 0) === :ok
      assert elem(result, 1) |> is_boolean
    end

    test "serialization", context do
      feature = context[:useful_feature]
      serialized_feature = context[:serialized_feature]

      assert(Iodized.Feature.json(feature) === serialized_feature)
    end

    test "deserialization", context do
      feature = context[:useful_feature]
      serialized_feature = context[:serialized_feature]

      assert(Iodized.Feature.from_json(serialized_feature) == feature)
    end

    test "do?/2 is false when no state is sent and master_switch_state is nil", context do
      feature = context[:useful_feature]
      state = context[:dummy_state]
      {:ok, result} = Iodized.Feature.do?(feature, state)
      refute(result)
    end

    test "do?/2 is true when master_switch_state is true", context do
      feature = context[:always_on_feature]
      state = context[:dummy_state]
      {:ok, result} = Iodized.Feature.do?(feature, state)
      assert(result)
    end

    test "do?/2 is true when master_switch_state is false", context do
      feature = context[:always_off_feature]
      state = context[:dummy_state]
      {:ok, result} = Iodized.Feature.do?(feature, state)
      refute(result)
    end

    test "do/?2 is true when the logic says so", context do
      feature = context[:useful_feature]
      state = HashDict.new |> HashDict.put("username", "paj")
      {:ok, result} = Iodized.Feature.do?(feature, state)
      assert(result)
    end

    test "do/?2 is false when the logic says so", context do
      feature = context[:useful_feature]
      state = HashDict.new |> HashDict.put("username", "madlep")
      {:ok, result} = Iodized.Feature.do?(feature, state)
      refute(result)
    end

    test "valid_title?/2 is true when lowercase alphanumeric with underscores or dashes" do
      assert Iodized.Feature.valid_title?("abc123_valid-title")
    end

    test "valid_title?/2 is false when an invalid character is in the title" do
      refute Iodized.Feature.valid_title?("abc123 invalid-title")
      refute Iodized.Feature.valid_title?("XYZ")
    end
  end
end


Non-existing file in multipart

Non-existing file in multipart

defmodule Tesla.MultipartTest do
  use ExUnit.Case

  alias Tesla.Multipart

  test "headers" do
    mp =
      Multipart.new

    headers = Multipart.headers(mp)

    assert headers == ["Content-Type": "multipart/form-data; boundary=#{mp.boundary}"]
  end

  test "add content-type param" do
    mp =
      Multipart.new
      |> Multipart.add_content_type_param("charset=utf-8")

    headers = Multipart.headers(mp)

    assert headers == ["Content-Type": "multipart/form-data; boundary=#{mp.boundary}; charset=utf-8"]
  end

  test "add content-type params" do
    mp =
      Multipart.new
      |> Multipart.add_content_type_param("charset=utf-8")
      |> Multipart.add_content_type_param("foo=bar")

    headers = Multipart.headers(mp)

    assert headers == ["Content-Type": "multipart/form-data; boundary=#{mp.boundary}; charset=utf-8; foo=bar"]
  end

  test "add_field" do
    mp =
      Multipart.new
      |> Multipart.add_field("foo", "bar")

    body = Multipart.body(mp) |> Enum.join

    assert body == """
--#{mp.boundary}\r
Content-Disposition: form-data; name="foo"\r
\r
bar\r
--#{mp.boundary}--\r
"""
  end

  test "add_field with extra headers" do
    mp =
      Multipart.new
      |> Multipart.add_field("foo", "bar", headers: [{:"Content-Id", 1}, {:"Content-Type", "text/plain"}])

    body = Multipart.body(mp) |> Enum.join

    assert body == """
--#{mp.boundary}\r
Content-Id: 1\r
Content-Type: text/plain\r
Content-Disposition: form-data; name="foo"\r
\r
bar\r
--#{mp.boundary}--\r
"""
  end

  test "add_file (filename only)" do
    mp =
      Multipart.new
      |> Multipart.add_file("test/tesla/multipart_test_file.sh")

    body = Multipart.body(mp) |> Enum.join

    assert body == """
--#{mp.boundary}\r
Content-Disposition: form-data; name="file"; filename="multipart_test_file.sh"\r
\r
#!/usr/bin/env bash
echo "test multipart file"
\r
--#{mp.boundary}--\r
"""
  end

  test "add_file (filename with name)" do
    mp =
      Multipart.new
      |> Multipart.add_file("test/tesla/multipart_test_file.sh", name: "foobar")

    body = Multipart.body(mp) |> Enum.join

    assert body == """
--#{mp.boundary}\r
Content-Disposition: form-data; name="foobar"; filename="multipart_test_file.sh"\r
\r
#!/usr/bin/env bash
echo "test multipart file"
\r
--#{mp.boundary}--\r
"""
  end

  test "add_file (custom filename)" do
    mp =
      Multipart.new
      |> Multipart.add_file("test/tesla/multipart_test_file.sh", filename: "custom.png")

    body = Multipart.body(mp) |> Enum.join

    assert body == """
--#{mp.boundary}\r
Content-Disposition: form-data; name="file"; filename="custom.png"\r
\r
#!/usr/bin/env bash
echo "test multipart file"
\r
--#{mp.boundary}--\r
"""
  end

  test "add_file (filename with name, extra headers)" do
    mp =
      Multipart.new
      |> Multipart.add_file("test/tesla/multipart_test_file.sh", name: "foobar", headers: [{:"Content-Id", 1}, {:"Content-Type", "text/plain"}])
    body = Multipart.body(mp) |> Enum.join

    assert body == """
--#{mp.boundary}\r
Content-Id: 1\r
Content-Type: text/plain\r
Content-Disposition: form-data; name="foobar"; filename="multipart_test_file.sh"\r
\r
#!/usr/bin/env bash
echo "test multipart file"
\r
--#{mp.boundary}--\r
"""
  end

  test "add_file (detect content type)" do
    mp =
      Multipart.new
      |> Multipart.add_file("test/tesla/multipart_test_file.sh", detect_content_type: true)

    body = Multipart.body(mp) |> Enum.join

    assert body == """
--#{mp.boundary}\r
Content-Type: application/x-sh\r
Content-Disposition: form-data; name="file"; filename="multipart_test_file.sh"\r
\r
#!/usr/bin/env bash
echo "test multipart file"
\r
--#{mp.boundary}--\r
"""
  end

  test "add_file (detect content type overrides given header)" do
    mp =
      Multipart.new
      |> Multipart.add_file("test/tesla/multipart_test_file.sh", detect_content_type: true, headers: [{:"Content-Type", "foo/bar"}])

    body = Multipart.body(mp) |> Enum.join

    assert body == """
--#{mp.boundary}\r
Content-Type: application/x-sh\r
Content-Disposition: form-data; name="file"; filename="multipart_test_file.sh"\r
\r
#!/usr/bin/env bash
echo "test multipart file"
\r
--#{mp.boundary}--\r
"""
  end

  test "add_file_content" do
    mp =
      Multipart.new
      |> Multipart.add_file_content("file-data", "data.gif")

    body = Multipart.body(mp) |> Enum.join

    assert body == """
--#{mp.boundary}\r
Content-Disposition: form-data; name="file"; filename="data.gif"\r
\r
file-data\r
--#{mp.boundary}--\r
"""
  end

  test "add non-existing file" do
    mp =
      Multipart.new
      |> Multipart.add_file("i-do-not-exists.txt")

    assert_raise File.Error, fn ->
      mp |> Multipart.body |> Enum.to_list
    end
  end
end

defmodule Tesla.MultipartTest do
  use ExUnit.Case

  alias Tesla.Multipart

  test "headers" do
    mp =
      Multipart.new

    headers = Multipart.headers(mp)

    assert headers == ["Content-Type": "multipart/form-data; boundary=#{mp.boundary}"]
  end

  test "add content-type param" do
    mp =
      Multipart.new
      |> Multipart.add_content_type_param("charset=utf-8")

    headers = Multipart.headers(mp)

    assert headers == ["Content-Type": "multipart/form-data; boundary=#{mp.boundary}; charset=utf-8"]
  end

  test "add content-type params" do
    mp =
      Multipart.new
      |> Multipart.add_content_type_param("charset=utf-8")
      |> Multipart.add_content_type_param("foo=bar")

    headers = Multipart.headers(mp)

    assert headers == ["Content-Type": "multipart/form-data; boundary=#{mp.boundary}; charset=utf-8; foo=bar"]
  end

  test "add_field" do
    mp =
      Multipart.new
      |> Multipart.add_field("foo", "bar")

    body = Multipart.body(mp) |> Enum.join

    assert body == """
--#{mp.boundary}\r
Content-Disposition: form-data; name="foo"\r
\r
bar\r
--#{mp.boundary}--\r
"""
  end

  test "add_field with extra headers" do
    mp =
      Multipart.new
      |> Multipart.add_field("foo", "bar", headers: [{:"Content-Id", 1}, {:"Content-Type", "text/plain"}])

    body = Multipart.body(mp) |> Enum.join

    assert body == """
--#{mp.boundary}\r
Content-Id: 1\r
Content-Type: text/plain\r
Content-Disposition: form-data; name="foo"\r
\r
bar\r
--#{mp.boundary}--\r
"""
  end

  test "add_file (filename only)" do
    mp =
      Multipart.new
      |> Multipart.add_file("test/tesla/multipart_test_file.sh")

    body = Multipart.body(mp) |> Enum.join

    assert body == """
--#{mp.boundary}\r
Content-Disposition: form-data; name="file"; filename="multipart_test_file.sh"\r
\r
#!/usr/bin/env bash
echo "test multipart file"
\r
--#{mp.boundary}--\r
"""
  end

  test "add_file (filename with name)" do
    mp =
      Multipart.new
      |> Multipart.add_file("test/tesla/multipart_test_file.sh", name: "foobar")

    body = Multipart.body(mp) |> Enum.join

    assert body == """
--#{mp.boundary}\r
Content-Disposition: form-data; name="foobar"; filename="multipart_test_file.sh"\r
\r
#!/usr/bin/env bash
echo "test multipart file"
\r
--#{mp.boundary}--\r
"""
  end

  test "add_file (custom filename)" do
    mp =
      Multipart.new
      |> Multipart.add_file("test/tesla/multipart_test_file.sh", filename: "custom.png")

    body = Multipart.body(mp) |> Enum.join

    assert body == """
--#{mp.boundary}\r
Content-Disposition: form-data; name="file"; filename="custom.png"\r
\r
#!/usr/bin/env bash
echo "test multipart file"
\r
--#{mp.boundary}--\r
"""
  end

  test "add_file (filename with name, extra headers)" do
    mp =
      Multipart.new
      |> Multipart.add_file("test/tesla/multipart_test_file.sh", name: "foobar", headers: [{:"Content-Id", 1}, {:"Content-Type", "text/plain"}])
    body = Multipart.body(mp) |> Enum.join

    assert body == """
--#{mp.boundary}\r
Content-Id: 1\r
Content-Type: text/plain\r
Content-Disposition: form-data; name="foobar"; filename="multipart_test_file.sh"\r
\r
#!/usr/bin/env bash
echo "test multipart file"
\r
--#{mp.boundary}--\r
"""
  end

  test "add_file (detect content type)" do
    mp =
      Multipart.new
      |> Multipart.add_file("test/tesla/multipart_test_file.sh", detect_content_type: true)

    body = Multipart.body(mp) |> Enum.join

    assert body == """
--#{mp.boundary}\r
Content-Type: application/x-sh\r
Content-Disposition: form-data; name="file"; filename="multipart_test_file.sh"\r
\r
#!/usr/bin/env bash
echo "test multipart file"
\r
--#{mp.boundary}--\r
"""
  end

  test "add_file (detect content type overrides given header)" do
    mp =
      Multipart.new
      |> Multipart.add_file("test/tesla/multipart_test_file.sh", detect_content_type: true, headers: [{:"Content-Type", "foo/bar"}])

    body = Multipart.body(mp) |> Enum.join

    assert body == """
--#{mp.boundary}\r
Content-Type: application/x-sh\r
Content-Disposition: form-data; name="file"; filename="multipart_test_file.sh"\r
\r
#!/usr/bin/env bash
echo "test multipart file"
\r
--#{mp.boundary}--\r
"""
  end

  test "add_file_content" do
    mp =
      Multipart.new
      |> Multipart.add_file_content("file-data", "data.gif")

    body = Multipart.body(mp) |> Enum.join

    assert body == """
--#{mp.boundary}\r
Content-Disposition: form-data; name="file"; filename="data.gif"\r
\r
file-data\r
--#{mp.boundary}--\r
"""
  end
end


debug post summary.

debug post summary.

defmodule Ello.V3.Schema.ContentTypes do
  use Absinthe.Schema.Notation
  import Ello.V3.Schema.Helpers
  alias Ello.Core.Content.{
    Post,
    Love,
    Watch,
  }

  enum :stream_kind do
    value :recent
    value :featured
    value :trending
    value :shop
  end

  object :comment_stream do
    field :next, :string
    field :per_page, :integer
    field :is_last_page, :boolean
    field :comments, list_of(:comment)
  end

  object :comment do
    field :id, :id
    field :author, :user
    field :parent_post, :post
    field :created_at, :datetime
    field :assets, list_of(:asset)
    field :summary, list_of(:content_blocks), resolve: &post_summary/2
    field :content, list_of(:content_blocks), resolve: &post_content/2
  end

  object :love_stream do
    field :next, :string
    field :per_page, :integer
    field :is_last_page, :boolean
    field :loves, list_of(:love)
  end

  object :love do
    field :id, :id
    field :user, :user
    field :post, :post
    field :created_at, :datetime
  end

  object :post_stream do
    field :next, :string
    field :per_page, :integer
    field :is_last_page, :boolean
    field :posts, list_of(:post)
  end

  object :new_content do
    field :new_content, :boolean
  end

  object :post do
    field :id, :id
    field :token, :string
    field :created_at, :datetime
    field :reposted_source, :post
    field :assets, list_of(:asset)
    field :categories, list_of(:category)
    field :category_posts, list_of(:category_post)
    field :author, :user
    field :summary, list_of(:content_blocks), resolve: &post_summary/2
    field :content, list_of(:content_blocks), resolve: &post_content/2
    field :repost_content, list_of(:content_blocks), resolve: &repost_content/2
    field :post_stats, :post_stats, resolve: &source_self/2
    field :current_user_state, :post_current_user_state, resolve: &source_self/2
    field :artist_invite_submission, :artist_invite_submission, resolve: &artist_invite_submission/2
  end

  object :post_stats do
    field :loves_count, :integer, resolve: &loves_count/2
    field :comments_count, :integer, resolve: &comments_count/2
    field :reposts_count, :integer, resolve: &reposts_count/2
    field :views_count, :integer, resolve: &views_count/2
  end

  object :post_current_user_state do
    field :reposted, :boolean, resolve: &post_reposted/2
    field :loved, :boolean, resolve: &post_loved/2
    field :watching, :boolean, resolve: &post_watching/2
  end

  object :content_blocks do
    field :link_url, :string, resolve: &str_get/2
    field :kind, :string, resolve: &str_get/2
    field :data, :content_data, resolve: &str_get/2
    field :links, :content_links, resolve: &str_get/2
  end

  object :content_links do
    field :assets, :id, resolve: &str_get/2
  end

  scalar :content_data do
    parse &(&1)
    serialize &(&1)
  end

  object :watch do
    field :id, :id
    field :post, :post
  end

  defp post_summary(_, %{source: %{reposted_source: %{rendered_summary: summary}}}),
    do: {:ok, summary}
  defp post_summary(_, %{source: %{rendered_summary: post_summary}}),
    do: {:ok, post_summary}
  defp post_summary(_, %{source: source}) do
    IO.inspect(source)
    {:ok, "
debugging
"}
  end

  defp post_content(_, %{source: %{rendered_content: post_content}}),
    do: {:ok, post_content}

  defp post_reposted(_, %{source: %{repost_from_current_user: %Post{}}}), do: {:ok, true}
  defp post_reposted(_, _), do: {:ok, false}

  defp post_loved(_, %{source: %{love_from_current_user: %Love{deleted: deleted}}}), do: {:ok, !deleted}
  defp post_loved(_, _), do: {:ok, false}

  defp post_watching(_, %{source: %{watch_from_current_user: %Watch{}}}), do: {:ok, true}
  defp post_watching(_, _), do: {:ok, false}

  defp repost_content(_, %{source: %{reposted_source: %{rendered_content: c}}}), do: {:ok, c}
  defp repost_content(_, _), do: {:ok, []}

  defp artist_invite_submission(_, %{source: %{artist_invite_submission: %{id: _} = s}}),
    do: {:ok, s}
  defp artist_invite_submission(_, _), do: {:ok, nil}

  def loves_count(_, %{source: %{reposted_source: %{loves_count: count}}}), do: {:ok, count}
  def loves_count(_, %{source: %{loves_count: count}}), do: {:ok, count}

  def comments_count(_, %{source: %{reposted_source: %{comments_count: count}}}), do: {:ok, count}
  def comments_count(_, %{source: %{comments_count: count}}), do: {:ok, count}

  def reposts_count(_, %{source: %{reposted_source: %{reposts_count: count}}}), do: {:ok, count}
  def reposts_count(_, %{source: %{reposts_count: count}}), do: {:ok, count}

  def views_count(_, %{source: %{reposted_source: %{views_count: count}}}), do: {:ok, count}
  def views_count(_, %{source: %{views_count: count}}), do: {:ok, count}
end

defmodule Ello.V3.Schema.ContentTypes do
  use Absinthe.Schema.Notation
  import Ello.V3.Schema.Helpers
  alias Ello.Core.Content.{
    Post,
    Love,
    Watch,
  }

  enum :stream_kind do
    value :recent
    value :featured
    value :trending
    value :shop
  end

  object :comment_stream do
    field :next, :string
    field :per_page, :integer
    field :is_last_page, :boolean
    field :comments, list_of(:comment)
  end

  object :comment do
    field :id, :id
    field :author, :user
    field :parent_post, :post
    field :created_at, :datetime
    field :assets, list_of(:asset)
    field :summary, list_of(:content_blocks), resolve: &post_summary/2
    field :content, list_of(:content_blocks), resolve: &post_content/2
  end

  object :love_stream do
    field :next, :string
    field :per_page, :integer
    field :is_last_page, :boolean
    field :loves, list_of(:love)
  end

  object :love do
    field :id, :id
    field :user, :user
    field :post, :post
    field :created_at, :datetime
  end

  object :post_stream do
    field :next, :string
    field :per_page, :integer
    field :is_last_page, :boolean
    field :posts, list_of(:post)
  end

  object :new_content do
    field :new_content, :boolean
  end

  object :post do
    field :id, :id
    field :token, :string
    field :created_at, :datetime
    field :reposted_source, :post
    field :assets, list_of(:asset)
    field :categories, list_of(:category)
    field :category_posts, list_of(:category_post)
    field :author, :user
    field :summary, list_of(:content_blocks), resolve: &post_summary/2
    field :content, list_of(:content_blocks), resolve: &post_content/2
    field :repost_content, list_of(:content_blocks), resolve: &repost_content/2
    field :post_stats, :post_stats, resolve: &source_self/2
    field :current_user_state, :post_current_user_state, resolve: &source_self/2
    field :artist_invite_submission, :artist_invite_submission, resolve: &artist_invite_submission/2
  end

  object :post_stats do
    field :loves_count, :integer, resolve: &loves_count/2
    field :comments_count, :integer, resolve: &comments_count/2
    field :reposts_count, :integer, resolve: &reposts_count/2
    field :views_count, :integer, resolve: &views_count/2
  end

  object :post_current_user_state do
    field :reposted, :boolean, resolve: &post_reposted/2
    field :loved, :boolean, resolve: &post_loved/2
    field :watching, :boolean, resolve: &post_watching/2
  end

  object :content_blocks do
    field :link_url, :string, resolve: &str_get/2
    field :kind, :string, resolve: &str_get/2
    field :data, :content_data, resolve: &str_get/2
    field :links, :content_links, resolve: &str_get/2
  end

  object :content_links do
    field :assets, :id, resolve: &str_get/2
  end

  scalar :content_data do
    parse &(&1)
    serialize &(&1)
  end

  object :watch do
    field :id, :id
    field :post, :post
  end

  defp post_summary(_, %{source: %{reposted_source: %{rendered_summary: summary}}}),
    do: {:ok, summary}
  defp post_summary(_, %{source: %{rendered_summary: post_summary}}),
    do: {:ok, post_summary}

  defp post_content(_, %{source: %{rendered_content: post_content}}),
    do: {:ok, post_content}

  defp post_reposted(_, %{source: %{repost_from_current_user: %Post{}}}), do: {:ok, true}
  defp post_reposted(_, _), do: {:ok, false}

  defp post_loved(_, %{source: %{love_from_current_user: %Love{deleted: deleted}}}), do: {:ok, !deleted}
  defp post_loved(_, _), do: {:ok, false}

  defp post_watching(_, %{source: %{watch_from_current_user: %Watch{}}}), do: {:ok, true}
  defp post_watching(_, _), do: {:ok, false}

  defp repost_content(_, %{source: %{reposted_source: %{rendered_content: c}}}), do: {:ok, c}
  defp repost_content(_, _), do: {:ok, []}

  defp artist_invite_submission(_, %{source: %{artist_invite_submission: %{id: _} = s}}),
    do: {:ok, s}
  defp artist_invite_submission(_, _), do: {:ok, nil}

  def loves_count(_, %{source: %{reposted_source: %{loves_count: count}}}), do: {:ok, count}
  def loves_count(_, %{source: %{loves_count: count}}), do: {:ok, count}

  def comments_count(_, %{source: %{reposted_source: %{comments_count: count}}}), do: {:ok, count}
  def comments_count(_, %{source: %{comments_count: count}}), do: {:ok, count}

  def reposts_count(_, %{source: %{reposted_source: %{reposts_count: count}}}), do: {:ok, count}
  def reposts_count(_, %{source: %{reposts_count: count}}), do: {:ok, count}

  def views_count(_, %{source: %{reposted_source: %{views_count: count}}}), do: {:ok, count}
  def views_count(_, %{source: %{views_count: count}}), do: {:ok, count}
end


use characters for more clarity

use characters for more clarity

defmodule DNA do
  @doc """
  Transcribes a character list representing DNA nucleotides to RNA

  ## Examples

  iex> DNA.to_rna('ACTG')
  'ACUG'
  """
  def to_rna(dna) do
    Enum.map dna, transcribe &1
  end

  # T -> U
  defp transcribe(?T), do: ?U
  defp transcribe(n),  do: n
end

defmodule DNA do
  @doc """
  Transcribes a character list representing DNA nucleotides to RNA

  ## Examples

  iex> DNA.to_rna('ACTG')
  'ACUG'
  """
  def to_rna(dna) do
    Enum.map dna, transcribe &1
  end

  # T -> U
  defp transcribe(84), do: 85
  defp transcribe(n),  do: n
end


:memo:

:memo:

defmodule AtomStyleTweaksWeb.PageMetadata do
  @moduledoc """
  A system for easily setting metadata for the page before it is rendered.

  If you assign some metadata to the page before it is rendered:

  ```
  iex> PageMetadata.add(conn, foo: "bar")
  iex> hd(conn.assigns.page_metadata)
  [foo: "bar"]
  ```

  And add the `PageMetadata.render/1` call to the layout template:

  ```html
  <html>
    <head>
      <%= PageMetadata.render(@conn) %>
  ```

  It will show up in the rendered page:

  ```html
  <html>
    <head>
      <meta foo="bar">
  ```
  """
  use Phoenix.HTML

  import Plug.Conn, only: [assign: 3]

  @doc """
  Adds an item of metadata for the page.

  An item of metadata is a keyword list of attributes and their values to be rendered as a `meta`
  tag in the page. A list of keyword lists can be supplied to add multiple items of metadata to be
  rendered.
  """
  @spec add(Plug.Conn.t, list | keyword(String.t)) :: Plug.Conn.t
  def add(conn, []), do: assign(conn, :page_metadata, get(conn))
  def add(conn, list) do
    if Keyword.keyword?(list) do
      assign(conn, :page_metadata, [list | get(conn)])
    else
      Enum.reduce(list, conn, &(add(&2, &1)))
    end
  end

  @doc """
  Renders the metadata for the page, if it was set.

  It renders each item of metadata as an individual `meta` tag. This function should be called in
  the `head` section of the page layout template, typically
  `app_name_web/templates/layout/app.html.eex`.
  """
  @spec render(Plug.Conn.t) :: Phoenix.HTML.safe | nil
  def render(conn) do
    case conn.assigns[:page_metadata] do
      nil -> nil
      metadata -> Enum.map(metadata, fn(datum) -> tag(:meta, datum) end)
    end
  end

  defp default_metadata(conn) do
    [
      [property: "og:url", content: "#{conn.scheme}://#{conn.host}#{conn.request_path}"],
      [property: "og:site_name", content: Application.get_env(:atom_style_tweaks, :site_name)]
    ]
  end

  defp get(conn) do
    conn.assigns[:page_metadata] || default_metadata(conn)
  end
end

defmodule AtomStyleTweaksWeb.PageMetadata do
  @moduledoc """
  A system for easily setting metadata for the page before it is rendered.

  If you assign some metadata to the page before it is rendered:

  ```
  iex> PageMetadata.add(conn, foo: "bar")
  iex> hd(conn.assigns.page_metadata)
  [foo: "bar"]
  ```

  And add the `PageMetadata.render/1` call to the layout template:

  ```html
  <html>
    <head>
      <%= PageMetadata.render(@conn) %>
  ```

  It will show up in the rendered page:

  ```html
  <html>
    <head>
      <meta foo="bar">
  ```
  """
  use Phoenix.HTML

  import Plug.Conn, only: [assign: 3]

  @doc """
  Adds an item of metadata for the page.
  """
  @spec add(Plug.Conn.t, list | keyword(String.t)) :: Plug.Conn.t
  def add(conn, []), do: assign(conn, :page_metadata, get(conn))
  def add(conn, list) do
    if Keyword.keyword?(list) do
      assign(conn, :page_metadata, [list | get(conn)])
    else
      Enum.reduce(list, conn, &(add(&2, &1)))
    end
  end

  @doc """
  Renders the metadata for the page, if it was set.
  """
  @spec render(Plug.Conn.t) :: Phoenix.HTML.safe | nil
  def render(conn) do
    case conn.assigns[:page_metadata] do
      nil -> nil
      metadata -> Enum.map(metadata, fn(datum) -> tag(:meta, datum) end)
    end
  end

  defp default_metadata(conn) do
    [
      [property: "og:url", content: "#{conn.scheme}://#{conn.host}#{conn.request_path}"],
      [property: "og:site_name", content: Application.get_env(:atom_style_tweaks, :site_name)]
    ]
  end

  defp get(conn) do
    conn.assigns[:page_metadata] || default_metadata(conn)
  end
end


Update parallel compiler callback documentation

defmodule Kernel.ParallelCompiler do
  alias :orddict, as: OrdDict

  @moduledoc """
  A module responsible for compiling files in parallel.
  """

  defmacrop default_callback, do: quote(do: fn x, exit_status -> x end)

  @doc """
  Compiles the given files.

  Those files are compiled in parallel and can automatically
  detect dependencies between them. Once a dependency is found,
  the current file stops being compiled until the dependency is
  resolved.

  A callback that is invoked every time a file is compiled
  with its name and an exit_status as arguments. The exit_status
  is :undefined if the compilation succeeded and an integer if
  it failed.
  """
  def files(files, callback // default_callback) do
    spawn_compilers(files, nil, callback)
  end

  @doc """
  Compiles the given files to the given path.
  Read files/2 for more information.
  """
  def files_to_path(files, path, callback // default_callback) when is_binary(path) do
    spawn_compilers(files, path, callback)
  end

  defp spawn_compilers(files, path, callback) do
    Code.ensure_loaded(Kernel.ErrorHandler)
    schedulers = max(:erlang.system_info(:schedulers_online), 2)
    spawn_compilers(files, path, callback, [], [], schedulers, [])
  end

  # We already have 4 currently running, don't spawn new ones
  defp spawn_compilers(files, output, callback, waiting, queued, schedulers, result) when
      length(queued) - length(waiting) >= schedulers do
    wait_for_messages(files, output, callback, waiting, queued, schedulers, result)
  end

  # Spawn a compiler for each file in the list until we reach the limit
  defp spawn_compilers([h|t], output, callback, waiting, queued, schedulers, result) do
    parent = self()

    child  = spawn_link fn ->
      :erlang.put(:elixir_compiler_pid, parent)
      :erlang.put(:elixir_ensure_compiled, true)
      :erlang.process_flag(:error_handler, Kernel.ErrorHandler)

      try do
        if output do
          :elixir_compiler.file_to_path(h, output)
        else
          :elixir_compiler.file(h)
        end
        parent <- { :compiled, self(), h, :erlang.get(:exit_status) }
      catch
        kind, reason ->
          parent <- { :failure, self(), kind, reason, System.stacktrace }
      end
    end

    spawn_compilers(t, output, callback, waiting, [{child,h}|queued], schedulers, result)
  end

  # No more files, nothing waiting, queue is empty, we are done
  defp spawn_compilers([], _output, _callback, [], [], _schedulers, result), do: result

  # Queued x, waiting for x: POSSIBLE ERROR! Release processes so we get the failures
  defp spawn_compilers([], output, callback, waiting, queued, schedulers, result) when length(waiting) == length(queued) do
    Enum.each queued, fn { child, _ } -> child <- { :release, self() } end
    wait_for_messages([], output, callback, waiting, queued, schedulers, result)
  end

  # No more files, but queue and waiting are not full or do not match
  defp spawn_compilers([], output, callback, waiting, queued, schedulers, result) do
    wait_for_messages([], output, callback, waiting, queued, schedulers, result)
  end

  # Wait for messages from child processes
  defp wait_for_messages(files, output, callback, waiting, queued, schedulers, result) do
    receive do
      { :compiled, child, file, exit_status } ->
        callback.(file, exit_status)
        new_queued  = List.keydelete(queued, child, 0)
        # Sometimes we may have spurious entries in the waiting
        # list because someone invoked try/rescue UndefinedFunctionError
        new_waiting = List.keydelete(waiting, child, 0)
        spawn_compilers(files, output, callback, new_waiting, new_queued, schedulers, result)
      { :module_available, _child, module, binary } ->
        new_waiting = release_waiting_processes(module, waiting)
        new_result  = [{module, binary}|result]
        wait_for_messages(files, output, callback, new_waiting, queued, schedulers, new_result)
      { :waiting, child, on } ->
        new_waiting = OrdDict.store(child, on, waiting)
        spawn_compilers(files, output, callback, new_waiting, queued, schedulers, result)
      { :failure, child, kind, reason, stacktrace } ->
        if many_missing?(child, files, waiting, queued) do
          IO.puts "== Compilation failed =="
          IO.puts "Compilation failed on the following files:\n"

          Enum.each Enum.reverse(queued), fn { pid, file } ->
            case List.keyfind(waiting, pid, 0) do
              { _, mod } -> IO.puts "* #{file} is missing module #{inspect mod}"
              _ -> :ok
            end
          end

          IO.puts "\nThe first failure is shown below..."
        end

        {^child, file} = List.keyfind(queued, child, 0)
        IO.puts "== Compilation error on file #{file} =="
        :erlang.raise(kind, reason, stacktrace)
    end
  end

  defp many_missing?(child, files, waiting, queued) do
    waiting_length = length(waiting)

    match?({ ^child, _ }, List.keyfind(waiting, child, 0)) and
      waiting_length > 1 and files == [] and
      waiting_length == length(queued)
  end

  # Release waiting processes that are waiting for the given module
  defp release_waiting_processes(module, waiting) do
    Enum.filter waiting, fn { child, waiting_module } ->
      if waiting_module == module do
        child <- { :release, self() }
        false
      else
        true
      end
    end
  end
end

defmodule Kernel.ParallelCompiler do
  alias :orddict, as: OrdDict

  @moduledoc """
  A module responsible for compiling files in parallel.
  """

  defmacrop default_callback, do: quote(do: fn x, exit_status -> x end)

  @doc """
  Compiles the given files.

  Those files are compiled in parallel and can automatically
  detect dependencies between them. Once a dependency is found,
  the current file stops being compiled until the dependency is
  resolved.

  A callback that is invoked every time a file is compiled
  with its name can be optionally given as argument.
  """
  def files(files, callback // default_callback) do
    spawn_compilers(files, nil, callback)
  end

  @doc """
  Compiles the given files to the given path.
  Read files/2 for more information.
  """
  def files_to_path(files, path, callback // default_callback) when is_binary(path) do
    spawn_compilers(files, path, callback)
  end

  defp spawn_compilers(files, path, callback) do
    Code.ensure_loaded(Kernel.ErrorHandler)
    schedulers = max(:erlang.system_info(:schedulers_online), 2)
    spawn_compilers(files, path, callback, [], [], schedulers, [])
  end

  # We already have 4 currently running, don't spawn new ones
  defp spawn_compilers(files, output, callback, waiting, queued, schedulers, result) when
      length(queued) - length(waiting) >= schedulers do
    wait_for_messages(files, output, callback, waiting, queued, schedulers, result)
  end

  # Spawn a compiler for each file in the list until we reach the limit
  defp spawn_compilers([h|t], output, callback, waiting, queued, schedulers, result) do
    parent = self()

    child  = spawn_link fn ->
      :erlang.put(:elixir_compiler_pid, parent)
      :erlang.put(:elixir_ensure_compiled, true)
      :erlang.process_flag(:error_handler, Kernel.ErrorHandler)

      try do
        if output do
          :elixir_compiler.file_to_path(h, output)
        else
          :elixir_compiler.file(h)
        end
        parent <- { :compiled, self(), h, :erlang.get(:exit_status) }
      catch
        kind, reason ->
          parent <- { :failure, self(), kind, reason, System.stacktrace }
      end
    end

    spawn_compilers(t, output, callback, waiting, [{child,h}|queued], schedulers, result)
  end

  # No more files, nothing waiting, queue is empty, we are done
  defp spawn_compilers([], _output, _callback, [], [], _schedulers, result), do: result

  # Queued x, waiting for x: POSSIBLE ERROR! Release processes so we get the failures
  defp spawn_compilers([], output, callback, waiting, queued, schedulers, result) when length(waiting) == length(queued) do
    Enum.each queued, fn { child, _ } -> child <- { :release, self() } end
    wait_for_messages([], output, callback, waiting, queued, schedulers, result)
  end

  # No more files, but queue and waiting are not full or do not match
  defp spawn_compilers([], output, callback, waiting, queued, schedulers, result) do
    wait_for_messages([], output, callback, waiting, queued, schedulers, result)
  end

  # Wait for messages from child processes
  defp wait_for_messages(files, output, callback, waiting, queued, schedulers, result) do
    receive do
      { :compiled, child, file, exit_status } ->
        callback.(file, exit_status)
        new_queued  = List.keydelete(queued, child, 0)
        # Sometimes we may have spurious entries in the waiting
        # list because someone invoked try/rescue UndefinedFunctionError
        new_waiting = List.keydelete(waiting, child, 0)
        spawn_compilers(files, output, callback, new_waiting, new_queued, schedulers, result)
      { :module_available, _child, module, binary } ->
        new_waiting = release_waiting_processes(module, waiting)
        new_result  = [{module, binary}|result]
        wait_for_messages(files, output, callback, new_waiting, queued, schedulers, new_result)
      { :waiting, child, on } ->
        new_waiting = OrdDict.store(child, on, waiting)
        spawn_compilers(files, output, callback, new_waiting, queued, schedulers, result)
      { :failure, child, kind, reason, stacktrace } ->
        if many_missing?(child, files, waiting, queued) do
          IO.puts "== Compilation failed =="
          IO.puts "Compilation failed on the following files:\n"

          Enum.each Enum.reverse(queued), fn { pid, file } ->
            case List.keyfind(waiting, pid, 0) do
              { _, mod } -> IO.puts "* #{file} is missing module #{inspect mod}"
              _ -> :ok
            end
          end

          IO.puts "\nThe first failure is shown below..."
        end

        {^child, file} = List.keyfind(queued, child, 0)
        IO.puts "== Compilation error on file #{file} =="
        :erlang.raise(kind, reason, stacktrace)
    end
  end

  defp many_missing?(child, files, waiting, queued) do
    waiting_length = length(waiting)

    match?({ ^child, _ }, List.keyfind(waiting, child, 0)) and
      waiting_length > 1 and files == [] and
      waiting_length == length(queued)
  end

  # Release waiting processes that are waiting for the given module
  defp release_waiting_processes(module, waiting) do
    Enum.filter waiting, fn { child, waiting_module } ->
      if waiting_module == module do
        child <- { :release, self() }
        false
      else
        true
      end
    end
  end
end


Fix heisentest

Fix heisentest

Code.require_file("test_helper.exs", __DIR__)

defmodule SupervisorTest do
  use ExUnit.Case, async: true

  defmodule Stack do
    use GenServer

    def start_link({state, opts}) do
      GenServer.start_link(__MODULE__, state, opts)
    end

    def init(args) do
      {:ok, args}
    end

    def handle_call(:pop, _from, [h | t]) do
      {:reply, h, t}
    end

    def handle_call(:stop, _from, stack) do
      # There is a race condition between genserver terminations.
      # So we will explicitly unregister it here.
      try do
        self() |> Process.info(:registered_name) |> elem(1) |> Process.unregister()
      rescue
        _ -> :ok
      end

      {:stop, :normal, :ok, stack}
    end

    def handle_cast({:push, h}, t) do
      {:noreply, [h | t]}
    end
  end

  defmodule Stack.Sup do
    use Supervisor

    def init(pair) do
      Supervisor.init([{Stack, pair}], strategy: :one_for_one)
    end
  end

  test "generates child_spec/1" do
    assert Stack.Sup.child_spec([:hello]) == %{
             id: Stack.Sup,
             start: {Stack.Sup, :start_link, [[:hello]]},
             type: :supervisor
           }

    defmodule CustomSup do
      use Supervisor,
        id: :id,
        restart: :temporary,
        start: {:foo, :bar, []}

      def init(arg) do
        arg
      end
    end

    assert CustomSup.child_spec([:hello]) == %{
             id: :id,
             restart: :temporary,
             start: {:foo, :bar, []},
             type: :supervisor
           }
  end

  test "child_spec/2" do
    assert Supervisor.child_spec(Task, []) ==
             %{id: Task, restart: :temporary, start: {Task, :start_link, [[]]}}

    assert Supervisor.child_spec({Task, :foo}, []) ==
             %{id: Task, restart: :temporary, start: {Task, :start_link, [:foo]}}

    assert Supervisor.child_spec(%{id: Task}, []) == %{id: Task}

    assert Supervisor.child_spec(
             Task,
             id: :foo,
             start: {:foo, :bar, []},
             restart: :permanent,
             shutdown: :infinity
           ) == %{id: :foo, start: {:foo, :bar, []}, restart: :permanent, shutdown: :infinity}

    message = ~r"The module SupervisorTest was given as a child.*\nbut it does not implement"m

    assert_raise ArgumentError, message, fn ->
      Supervisor.child_spec(SupervisorTest, [])
    end

    message = ~r"The module Unknown was given as a child.*but it does not exist"m

    assert_raise ArgumentError, message, fn ->
      Supervisor.child_spec(Unknown, [])
    end

    message = ~r"supervisors expect each child to be one of"

    assert_raise ArgumentError, message, fn ->
      Supervisor.child_spec("other", [])
    end
  end

  test "init/2" do
    flags = %{intensity: 3, period: 5, strategy: :one_for_one, auto_shutdown: :never}
    children = [%{id: Task, restart: :temporary, start: {Task, :start_link, [[]]}}]
    assert Supervisor.init([Task], strategy: :one_for_one) == {:ok, {flags, children}}

    flags = %{intensity: 1, period: 2, strategy: :one_for_all, auto_shutdown: :never}
    children = [%{id: Task, restart: :temporary, start: {Task, :start_link, [:foo]}}]

    assert Supervisor.init(
             [{Task, :foo}],
             strategy: :one_for_all,
             max_restarts: 1,
             max_seconds: 2
           ) == {:ok, {flags, children}}

    assert_raise ArgumentError, "expected :strategy option to be given", fn ->
      Supervisor.init([], [])
    end
  end

  test "init/2 with old and new child specs" do
    flags = %{intensity: 3, period: 5, strategy: :one_for_one, auto_shutdown: :never}

    children = [
      %{id: Task, restart: :temporary, start: {Task, :start_link, [[]]}},
      old_spec = {Task, {Task, :start_link, []}, :permanent, 5000, :worker, [Task]}
    ]

    assert Supervisor.init([Task, old_spec], strategy: :one_for_one) ==
             {:ok, {flags, children}}
  end

  test "start_link/2 with via" do
    Supervisor.start_link([], strategy: :one_for_one, name: {:via, :global, :via_sup})
    assert Supervisor.which_children({:via, :global, :via_sup}) == []
  end

  test "start_link/3 with global" do
    Supervisor.start_link([], strategy: :one_for_one, name: {:global, :global_sup})
    assert Supervisor.which_children({:global, :global_sup}) == []
  end

  test "start_link/3 with local" do
    Supervisor.start_link([], strategy: :one_for_one, name: :my_sup)
    assert Supervisor.which_children(:my_sup) == []
  end

  test "start_link/2" do
    children = [{Stack, {[:hello], [name: :dyn_stack]}}]
    {:ok, pid} = Supervisor.start_link(children, strategy: :one_for_one)

    wait_until_registered(:dyn_stack)
    assert GenServer.call(:dyn_stack, :pop) == :hello
    assert GenServer.call(:dyn_stack, :stop) == :ok

    wait_until_registered(:dyn_stack)
    assert GenServer.call(:dyn_stack, :pop) == :hello
    Supervisor.stop(pid)

    assert_raise ArgumentError, ~r"expected :name option to be one of the following:", fn ->
      name = "my_gen_server_name"
      Supervisor.start_link(children, name: name, strategy: :one_for_one)
    end

    assert_raise ArgumentError, ~r"expected :name option to be one of the following:", fn ->
      name = {:invalid_tuple, "my_gen_server_name"}
      Supervisor.start_link(children, name: name, strategy: :one_for_one)
    end

    assert_raise ArgumentError, ~r"expected :name option to be one of the following:", fn ->
      name = {:via, "Via", "my_gen_server_name"}
      Supervisor.start_link(children, name: name, strategy: :one_for_one)
    end
  end

  test "start_link/2 with old and new specs" do
    children = [
      {Stack, {[:hello], []}},
      {:old_stack, {SupervisorTest.Stack, :start_link, [{[:hello], []}]}, :permanent, 5000,
       :worker, [SupervisorTest.Stack]}
    ]

    {:ok, _} = Supervisor.start_link(children, strategy: :one_for_one)
  end

  test "start_link/3" do
    {:ok, pid} = Supervisor.start_link(Stack.Sup, {[:hello], [name: :stat_stack]})
    wait_until_registered(:stat_stack)
    assert GenServer.call(:stat_stack, :pop) == :hello
    Supervisor.stop(pid)
  end

  describe "start_child/2" do
    test "supports old child spec" do
      {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)
      child = {Task, {Task, :start_link, [fn -> :ok end]}, :temporary, 5000, :worker, [Task]}
      assert {:ok, pid} = Supervisor.start_child(pid, child)
      assert is_pid(pid)
    end

    test "supports new child spec as tuple" do
      {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)
      child = %{id: Task, restart: :temporary, start: {Task, :start_link, [fn -> :ok end]}}
      assert {:ok, pid} = Supervisor.start_child(pid, child)
      assert is_pid(pid)
    end

    test "supports new child spec" do
      {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)
      child = {Task, fn -> :timer.sleep(:infinity) end}
      assert {:ok, pid} = Supervisor.start_child(pid, child)
      assert is_pid(pid)
    end

    test "with invalid child spec" do
      {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)

      assert Supervisor.start_child(pid, %{}) == {:error, :missing_id}
      assert Supervisor.start_child(pid, {1, 2, 3, 4, 5, 6}) == {:error, {:invalid_mfa, 2}}

      assert Supervisor.start_child(pid, %{id: 1, start: {Task, :foo, :bar}}) ==
               {:error, {:invalid_mfa, {Task, :foo, :bar}}}

      assert Supervisor.start_child(pid, %{id: 1, start: {Task, :foo, [:bar]}, shutdown: -1}) ==
               {:error, {:invalid_shutdown, -1}}
    end

    test "with valid child spec" do
      Process.flag(:trap_exit, true)

      {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)

      for n <- 0..1 do
        assert {:ok, child_pid} =
                 Supervisor.start_child(pid, %{
                   id: n,
                   start: {Task, :start_link, [fn -> Process.sleep(:infinity) end]},
                   shutdown: n
                 })

        assert_kill(child_pid, :shutdown)
      end
    end
  end

  test "child life-cycle" do
    {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)

    assert Supervisor.which_children(pid) == []
    assert Supervisor.count_children(pid) == %{specs: 0, active: 0, supervisors: 0, workers: 0}

    child_spec = Supervisor.child_spec({Stack, {[:hello], []}}, [])
    {:ok, stack} = Supervisor.start_child(pid, child_spec)
    assert GenServer.call(stack, :pop) == :hello

    assert Supervisor.which_children(pid) ==
             [{SupervisorTest.Stack, stack, :worker, [SupervisorTest.Stack]}]

    assert Supervisor.count_children(pid) == %{specs: 1, active: 1, supervisors: 0, workers: 1}

    assert Supervisor.delete_child(pid, Stack) == {:error, :running}
    assert Supervisor.terminate_child(pid, Stack) == :ok

    {:ok, stack} = Supervisor.restart_child(pid, Stack)
    assert GenServer.call(stack, :pop) == :hello

    assert Supervisor.terminate_child(pid, Stack) == :ok
    assert Supervisor.delete_child(pid, Stack) == :ok
    Supervisor.stop(pid)
  end

  defp wait_until_registered(name) do
    unless Process.whereis(name) do
      wait_until_registered(name)
    end
  end

  defp assert_kill(pid, reason) do
    ref = Process.monitor(pid)
    Process.exit(pid, reason)
    assert_receive {:DOWN, ^ref, _, _, _}
  end
end

Code.require_file("test_helper.exs", __DIR__)

defmodule SupervisorTest do
  use ExUnit.Case, async: true

  defmodule Stack do
    use GenServer

    def start_link({state, opts}) do
      GenServer.start_link(__MODULE__, state, opts)
    end

    def init(args) do
      {:ok, args}
    end

    def handle_call(:pop, _from, [h | t]) do
      {:reply, h, t}
    end

    def handle_call(:stop, _from, stack) do
      # There is a race condition between genserver terminations.
      # So we will explicitly unregister it here.
      try do
        self() |> Process.info(:registered_name) |> elem(1) |> Process.unregister()
      rescue
        _ -> :ok
      end

      {:stop, :normal, :ok, stack}
    end

    def handle_cast({:push, h}, t) do
      {:noreply, [h | t]}
    end
  end

  defmodule Stack.Sup do
    use Supervisor

    def init(pair) do
      Supervisor.init([{Stack, pair}], strategy: :one_for_one)
    end
  end

  test "generates child_spec/1" do
    assert Stack.Sup.child_spec([:hello]) == %{
             id: Stack.Sup,
             start: {Stack.Sup, :start_link, [[:hello]]},
             type: :supervisor
           }

    defmodule CustomSup do
      use Supervisor,
        id: :id,
        restart: :temporary,
        start: {:foo, :bar, []}

      def init(arg) do
        arg
      end
    end

    assert CustomSup.child_spec([:hello]) == %{
             id: :id,
             restart: :temporary,
             start: {:foo, :bar, []},
             type: :supervisor
           }
  end

  test "child_spec/2" do
    assert Supervisor.child_spec(Task, []) ==
             %{id: Task, restart: :temporary, start: {Task, :start_link, [[]]}}

    assert Supervisor.child_spec({Task, :foo}, []) ==
             %{id: Task, restart: :temporary, start: {Task, :start_link, [:foo]}}

    assert Supervisor.child_spec(%{id: Task}, []) == %{id: Task}

    assert Supervisor.child_spec(
             Task,
             id: :foo,
             start: {:foo, :bar, []},
             restart: :permanent,
             shutdown: :infinity
           ) == %{id: :foo, start: {:foo, :bar, []}, restart: :permanent, shutdown: :infinity}

    message = ~r"The module SupervisorTest was given as a child.*\nbut it does not implement"m

    assert_raise ArgumentError, message, fn ->
      Supervisor.child_spec(SupervisorTest, [])
    end

    message = ~r"The module Unknown was given as a child.*but it does not exist"m

    assert_raise ArgumentError, message, fn ->
      Supervisor.child_spec(Unknown, [])
    end

    message = ~r"supervisors expect each child to be one of"

    assert_raise ArgumentError, message, fn ->
      Supervisor.child_spec("other", [])
    end
  end

  test "init/2" do
    flags = %{intensity: 3, period: 5, strategy: :one_for_one, auto_shutdown: :never}
    children = [%{id: Task, restart: :temporary, start: {Task, :start_link, [[]]}}]
    assert Supervisor.init([Task], strategy: :one_for_one) == {:ok, {flags, children}}

    flags = %{intensity: 1, period: 2, strategy: :one_for_all, auto_shutdown: :never}
    children = [%{id: Task, restart: :temporary, start: {Task, :start_link, [:foo]}}]

    assert Supervisor.init(
             [{Task, :foo}],
             strategy: :one_for_all,
             max_restarts: 1,
             max_seconds: 2
           ) == {:ok, {flags, children}}

    assert_raise ArgumentError, "expected :strategy option to be given", fn ->
      Supervisor.init([], [])
    end
  end

  test "init/2 with old and new child specs" do
    flags = %{intensity: 3, period: 5, strategy: :one_for_one, auto_shutdown: :never}

    children = [
      %{id: Task, restart: :temporary, start: {Task, :start_link, [[]]}},
      old_spec = {Task, {Task, :start_link, []}, :permanent, 5000, :worker, [Task]}
    ]

    assert Supervisor.init([Task, old_spec], strategy: :one_for_one) ==
             {:ok, {flags, children}}
  end

  test "start_link/2 with via" do
    Supervisor.start_link([], strategy: :one_for_one, name: {:via, :global, :via_sup})
    assert Supervisor.which_children({:via, :global, :via_sup}) == []
  end

  test "start_link/3 with global" do
    Supervisor.start_link([], strategy: :one_for_one, name: {:global, :global_sup})
    assert Supervisor.which_children({:global, :global_sup}) == []
  end

  test "start_link/3 with local" do
    Supervisor.start_link([], strategy: :one_for_one, name: :my_sup)
    assert Supervisor.which_children(:my_sup) == []
  end

  test "start_link/2" do
    children = [{Stack, {[:hello], [name: :dyn_stack]}}]
    {:ok, pid} = Supervisor.start_link(children, strategy: :one_for_one)

    wait_until_registered(:dyn_stack)
    assert GenServer.call(:dyn_stack, :pop) == :hello
    assert GenServer.call(:dyn_stack, :stop) == :ok

    wait_until_registered(:dyn_stack)
    assert GenServer.call(:dyn_stack, :pop) == :hello
    Supervisor.stop(pid)

    assert_raise ArgumentError, ~r"expected :name option to be one of the following:", fn ->
      name = "my_gen_server_name"
      Supervisor.start_link(children, name: name, strategy: :one_for_one)
    end

    assert_raise ArgumentError, ~r"expected :name option to be one of the following:", fn ->
      name = {:invalid_tuple, "my_gen_server_name"}
      Supervisor.start_link(children, name: name, strategy: :one_for_one)
    end

    assert_raise ArgumentError, ~r"expected :name option to be one of the following:", fn ->
      name = {:via, "Via", "my_gen_server_name"}
      Supervisor.start_link(children, name: name, strategy: :one_for_one)
    end
  end

  test "start_link/2 with old and new specs" do
    children = [
      {Stack, {[:hello], []}},
      {:old_stack, {SupervisorTest.Stack, :start_link, [{[:hello], []}]}, :permanent, 5000,
       :worker, [SupervisorTest.Stack]}
    ]

    {:ok, _} = Supervisor.start_link(children, strategy: :one_for_one)
  end

  test "start_link/3" do
    {:ok, pid} = Supervisor.start_link(Stack.Sup, {[:hello], [name: :stat_stack]})
    wait_until_registered(:stat_stack)
    assert GenServer.call(:stat_stack, :pop) == :hello
    Supervisor.stop(pid)
  end

  describe "start_child/2" do
    test "supports old child spec" do
      {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)
      child = {Task, {Task, :start_link, [fn -> :ok end]}, :temporary, 5000, :worker, [Task]}
      assert {:ok, pid} = Supervisor.start_child(pid, child)
      assert is_pid(pid)
    end

    test "supports new child spec as tuple" do
      {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)
      child = %{id: Task, restart: :temporary, start: {Task, :start_link, [fn -> :ok end]}}
      assert {:ok, pid} = Supervisor.start_child(pid, child)
      assert is_pid(pid)
    end

    test "supports new child spec" do
      {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)
      child = {Task, fn -> :timer.sleep(:infinity) end}
      assert {:ok, pid} = Supervisor.start_child(pid, child)
      assert is_pid(pid)
    end

    test "with invalid child spec" do
      {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)

      assert Supervisor.start_child(pid, %{}) == {:error, :missing_id}
      assert Supervisor.start_child(pid, {1, 2, 3, 4, 5, 6}) == {:error, {:invalid_mfa, 2}}

      assert Supervisor.start_child(pid, %{id: 1, start: {Task, :foo, :bar}}) ==
               {:error, {:invalid_mfa, {Task, :foo, :bar}}}

      assert Supervisor.start_child(pid, %{id: 1, start: {Task, :foo, [:bar]}, shutdown: -1}) ==
               {:error, {:invalid_shutdown, -1}}
    end

    test "with valid child spec" do
      Process.flag(:trap_exit, true)

      {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)

      for n <- 0..1 do
        assert {:ok, child_pid} =
                 Supervisor.start_child(pid, %{
                   id: n,
                   start: {Task, :start_link, [fn -> :ok end]},
                   shutdown: n
                 })

        assert_kill(child_pid, :shutdown)
      end
    end
  end

  test "child life-cycle" do
    {:ok, pid} = Supervisor.start_link([], strategy: :one_for_one)

    assert Supervisor.which_children(pid) == []
    assert Supervisor.count_children(pid) == %{specs: 0, active: 0, supervisors: 0, workers: 0}

    child_spec = Supervisor.child_spec({Stack, {[:hello], []}}, [])
    {:ok, stack} = Supervisor.start_child(pid, child_spec)
    assert GenServer.call(stack, :pop) == :hello

    assert Supervisor.which_children(pid) ==
             [{SupervisorTest.Stack, stack, :worker, [SupervisorTest.Stack]}]

    assert Supervisor.count_children(pid) == %{specs: 1, active: 1, supervisors: 0, workers: 1}

    assert Supervisor.delete_child(pid, Stack) == {:error, :running}
    assert Supervisor.terminate_child(pid, Stack) == :ok

    {:ok, stack} = Supervisor.restart_child(pid, Stack)
    assert GenServer.call(stack, :pop) == :hello

    assert Supervisor.terminate_child(pid, Stack) == :ok
    assert Supervisor.delete_child(pid, Stack) == :ok
    Supervisor.stop(pid)
  end

  defp wait_until_registered(name) do
    unless Process.whereis(name) do
      wait_until_registered(name)
    end
  end

  defp assert_kill(pid, reason) do
    ref = Process.monitor(pid)
    Process.exit(pid, reason)
    assert_receive {:DOWN, ^ref, _, _, _}
  end
end


Add heredocs indentation test to DocTest

Code.require_file "../test_helper.exs", __DIR__

defmodule ExUnit.DocTestTest.GoodModule do
  @doc """
  iex> test_fun
  1
  iex> test_fun + 1
  2
  """
  def test_fun, do: 1

  @doc """
  iex> a = 1
  iex> b = a + 2
  3
  iex> a + b
  4
  """
  def single_context, do: :ok

  @doc """
  iex> 1 + (fn() -> "" end).()
  ** (ArithmeticError) bad argument in arithmetic expression

  iex> 2 + (fn() -> :a end).()
  ** (ArithmeticError) bad argument in arithmetic expression
  """
  def two_exceptions, do: :ok

  @doc """
  iex> 1 + (fn() -> :a end).()
  ** (ArithmeticError) bad argument in arithmetic expression
  """
  def exception_test, do: :ok
end

defmodule ExUnit.DocTestTest.ExceptionModule do
  @doc """
  iex> 1 + ""
  ** (ArithmeticError) bad argument in arithmetic expression
  iex> 2 + ""
  ** (ArithmeticError) bad argument in arithmetic expression
  """
  def two_exceptions, do: :ok
end

defmodule ExUnit.DocTestTest.SomewhatGoodModuleWithOnly do
  @doc """
  iex> test_fun
  1
  iex> test_fun + 1
  2
  """
  def test_fun, do: 1

  @doc """
  iex> test_fun
  1
  iex> test_fun + 1
  1
  """
  def test_fun1, do: 1
end

defmodule ExUnit.DocTestTest.SomewhatGoodModuleWithExcept do
  @doc """
  iex> test_fun
  1
  iex> test_fun + 1
  2
  """
  def test_fun, do: 1

  @doc """
  iex> test_fun
  1
  iex> test_fun + 1
  1
  """
  def test_fun1, do: 1
end

defmodule ExUnit.DocTestTest.NoImport do
  @doc """
  iex> ExUnit.DocTestTest.NoImport.min(1, 2)
  2
  """
  def min(a, b), do: max(a, b)
end

defmodule ExUnit.DocTestTest.Invalid do
  @doc """
  iex> _a = 1
  1

  iex> _a + 1
  2
  """
  def no_leak, do: :ok
end

defmodule ExUnit.DocTestTest.IndentationHeredocs do
  @doc %B'''
  Receives a test and formats its failure.

  ## Examples

      iex> "  1\n  2\n"
      """
        1
        2
      """

  '''
  def heredocs, do: :ok
end

defmodule ExUnit.DocTestTest do
  use ExUnit.Case

  # This is intentional. The doctests in DocTest's docs fail
  # for demonstration purposes.
  # doctest ExUnit.DocTest

  doctest ExUnit.DocTestTest.GoodModule, import: true
  doctest ExUnit.DocTestTest.SomewhatGoodModuleWithOnly, only: [test_fun: 0], import: true
  doctest ExUnit.DocTestTest.SomewhatGoodModuleWithExcept, except: [test_fun1: 0], import: true
  doctest ExUnit.DocTestTest.NoImport

  assert_raise ExUnit.DocTest.Error, fn ->
    doctest ExUnit.DocTestTest.ExceptionModule
  end

  test :no_var_leak do
    assert_raise CompileError, %r"function '_a'/0 undefined", fn ->
      defmodule NeverCompiled do
        import ExUnit.DocTest
        doctest ExUnit.DocTestTest.Invalid
      end
    end
  end

  doctest ExUnit.DocTestTest.IndentationHeredocs
end

Code.require_file "../test_helper.exs", __DIR__

defmodule ExUnit.DocTestTest.GoodModule do
  @doc """
  iex> test_fun
  1
  iex> test_fun + 1
  2
  """
  def test_fun, do: 1

  @doc """
  iex> a = 1
  iex> b = a + 2
  3
  iex> a + b
  4
  """
  def single_context, do: :ok

  @doc """
  iex> 1 + (fn() -> "" end).()
  ** (ArithmeticError) bad argument in arithmetic expression

  iex> 2 + (fn() -> :a end).()
  ** (ArithmeticError) bad argument in arithmetic expression
  """
  def two_exceptions, do: :ok

  @doc """
  iex> 1 + (fn() -> :a end).()
  ** (ArithmeticError) bad argument in arithmetic expression
  """
  def exception_test, do: :ok
end

defmodule ExUnit.DocTestTest.ExceptionModule do
  @doc """
  iex> 1 + ""
  ** (ArithmeticError) bad argument in arithmetic expression
  iex> 2 + ""
  ** (ArithmeticError) bad argument in arithmetic expression
  """
  def two_exceptions, do: :ok
end

defmodule ExUnit.DocTestTest.SomewhatGoodModuleWithOnly do
  @doc """
  iex> test_fun
  1
  iex> test_fun + 1
  2
  """
  def test_fun, do: 1

  @doc """
  iex> test_fun
  1
  iex> test_fun + 1
  1
  """
  def test_fun1, do: 1
end

defmodule ExUnit.DocTestTest.SomewhatGoodModuleWithExcept do
  @doc """
  iex> test_fun
  1
  iex> test_fun + 1
  2
  """
  def test_fun, do: 1

  @doc """
  iex> test_fun
  1
  iex> test_fun + 1
  1
  """
  def test_fun1, do: 1
end

defmodule ExUnit.DocTestTest.NoImport do
  @doc """
  iex> ExUnit.DocTestTest.NoImport.min(1, 2)
  2
  """
  def min(a, b), do: max(a, b)
end

defmodule ExUnit.DocTestTest.Invalid do
  @doc """
  iex> _a = 1
  1

  iex> _a + 1
  2
  """
  def no_leak, do: :ok
end

defmodule ExUnit.DocTestTest do
  use ExUnit.Case

  # This is intentional. The doctests in DocTest's docs fail
  # for demonstration purposes.
  # doctest ExUnit.DocTest

  doctest ExUnit.DocTestTest.GoodModule, import: true
  doctest ExUnit.DocTestTest.SomewhatGoodModuleWithOnly, only: [test_fun: 0], import: true
  doctest ExUnit.DocTestTest.SomewhatGoodModuleWithExcept, except: [test_fun1: 0], import: true
  doctest ExUnit.DocTestTest.NoImport

  assert_raise ExUnit.DocTest.Error, fn ->
    doctest ExUnit.DocTestTest.ExceptionModule
  end

  test :no_var_leak do
    assert_raise CompileError, %r"function '_a'/0 undefined", fn ->
      defmodule NeverCompiled do
        import ExUnit.DocTest
        doctest ExUnit.DocTestTest.Invalid
      end
    end
  end
end


First draft `zero` RPC handler

First draft `zero` RPC handler

defmodule Farmbot.CeleryScript.Command.Zero do
  @moduledoc """
    Zero
  """

  alias Farmbot.CeleryScript.Command
  require Logger
  @behaviour Command

  @doc ~s"""
    Set axis current position to "0":
      args: %{axis: "x" | "y" | "z" | "all"}
      body: []
  """
  @spec run(%{axis: String.t}, []) :: no_return
  @lint {Credo.Check.Refactor.PipeChainStart, false}
  def run(%{axis: axis}, []) do
    case axis do
      "x" -> "F84 X1 Y0 Z0"
      "y" -> "F84 X0 Y1 Z0"
      "z" -> "F84 X0 Y0 Z1"
    end |> UartHan.write
  end
end

defmodule Farmbot.CeleryScript.Command.Zero do
  @moduledoc """
    Zero
  """

  alias Farmbot.CeleryScript.Command
  require Logger
  @behaviour Command

  @doc ~s"""
    Zero
    args: %{axis: axis},
    body: []
  """
  @spec run(%{axis: any}, []) :: no_return
  def run(%{axis: _axis}, []) do
    Logger.warn "ZERO IS TODO"
  end

end


try this rick

try this rick

defmodule Module.concat([Farmbot,System,"host"]) do
  @moduledoc false
  @behaviour Farmbot.System

  require IEx

  def reboot, do: :ok
  def power_off, do: :ok

  def factory_reset(reason) do
    files = path() |> File.ls!()
    Farmbot.System.FS.transaction fn() ->
      File.rm_rf files
      File.write("#{path()}/factory_reset_reason", reason)
    end, true
    IEx.pry
    System.halt(0)
  end

  defp path, do: Farmbot.System.FS.path()
end

defmodule Module.concat([Farmbot,System,"host"]) do
  @moduledoc false
  @behaviour Farmbot.System

  def reboot, do: :ok
  def power_off, do: :ok

  def factory_reset(reason) do
    files = path() |> File.ls!()
    Farmbot.System.FS.transaction fn() ->
      File.rm_rf files
      File.write("#{path()}/factory_reset_reason", reason)
    end, true
    System.halt(0)
  end

  defp path, do: Farmbot.System.FS.path()
end


snapshot update with `motionlevel` works now

defmodule EvercamMedia.MotionDetection.ComparatorHandler do
  use GenEvent
  require Logger
  alias EvercamMedia.Repo
  import Ecto.Query

  @moduledoc """
  TODO
  """

  def handle_event({:got_snapshot, data}, state) do
    {camera_exid, timestamp, image} = data
    image_byte_size = byte_size image
    Logger.info "Inside EvercamMedia.MotionDetection.ComparatorHandler -> handle_event"
    Logger.info "camera_exid=#{camera_exid}"

    camera_exid_last = "#{camera_exid}_last"
    camera_exid_previous = "#{camera_exid}_previous"

    # last_timestamp = result[:timestamp]
    # last_notes = result[:notes]

    last = ConCache.get(:cache, camera_exid_last)
    previous = ConCache.get(:cache, camera_exid_previous)

    last_image = last[:image]
    previous_image = previous[:image]

    Logger.info "last = #{last[:timestamp]}, previous = #{previous[:timestamp]}"

    if last_image && previous_image do
      EvercamMedia.MotionDetection.Lib.init
      motion_level = EvercamMedia.MotionDetection.Lib.compare(last_image,previous_image)
      Logger.info "motion_level = #{motion_level}"

      update_snapshot_status("#{camera_exid}", previous[:timestamp], motion_level)
    end

    {:ok, state}
  end

  def update_snapshot_status(camera_exid, seconds, motion_level) do
    camera = Repo.one! Camera.by_exid(camera_exid)
    tt = Timex.Date.from(seconds, :secs)
    # Timex.DateTime{calendar: :gregorian, day: 13, hour: 22, minute: 41, month: 10, ms: 0, second: 25, timezone: %Timex.TimezoneInfo{abbreviation: "UTC", from: :min, full_name: "UTC", offset_std: 0, offset_utc: 0, until: :max}, year: 2015}}
    year = tt.year
    month = tt.month
    day = tt.day

    hour = tt.hour
    min = tt.minute
    sec = tt.second
    usec = tt.ms

    date = {year, month, day}
    time = {hour, min, sec, usec}
    datetime = {date, time}

    date_str = date |> :erlang.tuple_to_list |> Enum.join
    time_str = time |> :erlang.tuple_to_list |> Enum.join

    Logger.info "date is #{date_str} and time is #{time_str}"

    data = Ecto.DateTime.cast(datetime)
    {_,timestamp} = data

    snapshot = Repo.one Snapshot.for_camera(camera.id,timestamp)
    # snapshot = Repo.one! Snapshot.for_camera(camera.id,timestamp)
    # Logger.info "update_snapshot_status snapshot.id=#{snapshot[:id]}"

    case snapshot do
      nil -> Logger.info "No snapshot for #{date_str} and #{time_str}"
      _ ->
        snapshot = %{snapshot | motionlevel: motion_level}
        Logger.info "Updating the snapshot #{snapshot.id}"
        Repo.update snapshot
    end
  end

  def handle_event(_, state) do
    {:ok, state}
  end

end

defmodule EvercamMedia.MotionDetection.ComparatorHandler do
  use GenEvent
  require Logger
  alias EvercamMedia.Repo
  import Ecto.Query

  @moduledoc """
  TODO
  """

  def handle_event({:got_snapshot, data}, state) do
    {camera_exid, timestamp, image} = data
    image_byte_size = byte_size image
    Logger.info "Inside EvercamMedia.MotionDetection.ComparatorHandler -> handle_event"
    Logger.info "camera_exid=#{camera_exid}"

    camera_exid_last = "#{camera_exid}_last"
    camera_exid_previous = "#{camera_exid}_previous"

    # last_timestamp = result[:timestamp]
    # last_notes = result[:notes]

    last = ConCache.get(:cache, camera_exid_last)
    previous = ConCache.get(:cache, camera_exid_previous)

    last_image = last[:image]
    previous_image = previous[:image]

    Logger.info "last = #{last[:timestamp]}, previous = #{previous[:timestamp]}"

    if last_image && previous_image do
      EvercamMedia.MotionDetection.Lib.init
      motion_level = EvercamMedia.MotionDetection.Lib.compare(last_image,previous_image)
      Logger.info "motion_level = #{motion_level}"

      update_snapshot_status("#{camera_exid}", last[:timestamp], motion_level)
    end

    {:ok, state}
  end

  def update_snapshot_status(camera_exid, seconds, motion_level) do
    camera = Repo.one! Camera.by_exid(camera_exid)
    tt = Timex.Date.from(seconds, :secs)
    # Timex.DateTime{calendar: :gregorian, day: 13, hour: 22, minute: 41, month: 10, ms: 0, second: 25, timezone: %Timex.TimezoneInfo{abbreviation: "UTC", from: :min, full_name: "UTC", offset_std: 0, offset_utc: 0, until: :max}, year: 2015}}
    year = tt.year
    month = tt.month
    day = tt.day

    hour = tt.hour
    min = tt.minute
    sec = tt.second
    usec = tt.ms

    date = {year, month, day}
    time = {hour, min, sec, usec}
    datetime = {date, time}

    date_str = date |> :erlang.tuple_to_list |> Enum.join
    time_str = time |> :erlang.tuple_to_list |> Enum.join

    Logger.info "date is #{date_str} and time is #{time_str}"

    data = Ecto.DateTime.cast(datetime)
    {_,timestamp} = data

    snapshot = Repo.one Snapshot.for_camera(camera.id,timestamp)
    # snapshot = Repo.one! Snapshot.for_camera(camera.id,timestamp)
    # Logger.info "update_snapshot_status snapshot.id=#{snapshot[:id]}"

    case snapshot do
      nil -> Logger.info "No snapshot for #{date_str} and #{time_str}"
      _ ->
        snapshot = %{snapshot | motionlevel: motion_level}
        Logger.info "Updating the snapshot #{snapshot.id}"
        Repo.update snapshot
    end
  end

  def handle_event(_, state) do
    {:ok, state}
  end

end


Fix start/end tags (#14)

Fix start/end tags (#14)

defmodule GoogleApi.Storage.Samples do
  @moduledoc """
  Documentation for GoogleApi.Storage.Samples.
  """

  @doc """
  List storage buckets for a project.

  ## Examples

      iex> GoogleApi.Storage.Samples.list_buckets("your_project_id")
      your_project_bucket1
      your_project_bucket2

  """
  def list_buckets(project_id) do
    {:ok, token} = Goth.Token.for_scope("https://www.googleapis.com/auth/cloud-platform")
    conn = GoogleApi.Storage.V1.Connection.new(token.token)
    {:ok, response} = GoogleApi.Storage.V1.Api.Buckets.storage_buckets_list(conn, project_id)
    Enum.each(response.items, &IO.puts(&1.id))
  end

  # [START storage_upload_file]
  @doc """
  List storage buckets for a project.

  ## Examples

      iex> GoogleApi.Storage.Samples.upload_file("bucket_id", "test/file.txt")
      Uploaded file.text to  https://www.googleapis.com/storage/v1/b/bucket_id/o/file.txt
      your_project_bucket2

  """
  def upload_file(bucket_id, file_path) do
    # Authenticate.
    {:ok, token} = Goth.Token.for_scope("https://www.googleapis.com/auth/cloud-platform")
    conn = GoogleApi.Storage.V1.Connection.new(token.token)

    # Make the API request.
    {:ok, object} = GoogleApi.Storage.V1.Api.Objects.storage_objects_insert_simple(
      conn,
      bucket_id,
      "multipart",
      %{name: Path.basename(file_path)},
      file_path
    )

    # Print the object.
    IO.puts("Uploaded #{object.name} to #{object.selfLink}")
  end
  # [END storage_upload_file]
end

defmodule GoogleApi.Storage.Samples do
  @moduledoc """
  Documentation for GoogleApi.Storage.Samples.
  """

  @doc """
  List storage buckets for a project.

  ## Examples

      iex> GoogleApi.Storage.Samples.list_buckets("your_project_id")
      your_project_bucket1
      your_project_bucket2

  """
  def list_buckets(project_id) do
    {:ok, token} = Goth.Token.for_scope("https://www.googleapis.com/auth/cloud-platform")
    conn = GoogleApi.Storage.V1.Connection.new(token.token)
    {:ok, response} = GoogleApi.Storage.V1.Api.Buckets.storage_buckets_list(conn, project_id)
    Enum.each(response.items, &IO.puts(&1.id))
  end

  # [start storage_upload_file]
  @doc """
  List storage buckets for a project.

  ## Examples

      iex> GoogleApi.Storage.Samples.upload_file("bucket_id", "test/file.txt")
      Uploaded file.text to  https://www.googleapis.com/storage/v1/b/bucket_id/o/file.txt
      your_project_bucket2

  """
  def upload_file(bucket_id, file_path) do
    # Authenticate.
    {:ok, token} = Goth.Token.for_scope("https://www.googleapis.com/auth/cloud-platform")
    conn = GoogleApi.Storage.V1.Connection.new(token.token)

    # Make the API request.
    {:ok, object} = GoogleApi.Storage.V1.Api.Objects.storage_objects_insert_simple(
      conn,
      bucket_id,
      "multipart",
      %{name: Path.basename(file_path)},
      file_path
    )

    # Print the object.
    IO.puts("Uploaded #{object.name} to #{object.selfLink}")
  end
  # [end storage_upload_file]
end


update config example

update config example

Signed-off-by: Adam Stokes <0a364f4bf549cc82d725fa7fd7ed34404be64079@ubuntu.com>

# -*- mode:toml; -*-

[config]
# Define options that can be configured during install
# along with setting a default recommended option

# Example, mysql, has options such as bind-address and
# backup_retention_count, make these editable and include
# dataset-size as is and make editable.

# Define what config options can be modified, these will use
# the existing config's defaults
"editable"               = ["bind-address",
                            "backup_retention_count",
                            "dataset-size"]

# User can change from default 0.0.0.0, we place our own
# recommendation here as well
"bind-address"           = "172.16.0.4"

# Change the backup retention from default of 7 to our
# recommended 5, also configurable at install.
"backup_retention_count" = 5

# -*- mode:toml; -*-

[config]
# Define options that can be configured during install
# along with setting a default recommended option

# Example, mysql, has options such as bind-address and
# backup_retention_count, make these editable and include
# dataset-size as is and make editable.

# Define what config options can be modified, these will use
# the existing config's defaults
"editable"               = ["bind-address", "backup_retention", "dataset-size"]

# User can change from default 0.0.0.0, we place our own
# recommendation here as well
"bind-address"           = "172.16.0.4"

# Change the backup retention from default of 7 to our
# recommended 5, also configurable at install.
"backup_retention_count" = 5


Test Template.engines returns a map

Test Template.engines returns a map

defmodule Phoenix.TemplateTest do
  use ExUnit.Case, async: true

  doctest Phoenix.Template
  alias Phoenix.Template

  @templates Path.expand("../fixtures/templates", __DIR__)

  test "engines/0" do
    assert is_map Template.engines
  end

  test "template_path_to_name/2" do
    path = "/var/www/templates/admin/users/show.html.eex"
    root = "/var/www/templates"
    assert Template.template_path_to_name(path, root) ==
           "admin/users/show.html"

    path = "/var/www/templates/users/show.html.eex"
    root = "/var/www/templates"
    assert Template.template_path_to_name(path, root) ==
           "users/show.html"

    path = "/var/www/templates/home.html.eex"
    root = "/var/www/templates"
    assert Template.template_path_to_name(path, root) ==
           "home.html"

    path = "/var/www/templates/home.html.haml"
    root = "/var/www/templates"
    assert Template.template_path_to_name(path, root) ==
           "home.html"
  end

  test "find_all/1 finds all templates in the iven root" do
    templates = Template.find_all @templates
    assert Path.join(@templates, "show.html.eex") in templates

    templates = Template.find_all Path.dirname(@templates)
    assert templates == []
  end

  test "hash/1 returns the hash for the given root" do
    assert is_binary Template.hash(@templates)
  end

  test "format_encoder/1 returns the formatter for a given template" do
    assert Template.format_encoder("hello.html") == Phoenix.HTML.Engine
    assert Template.format_encoder("hello.unknown") == nil
  end

  ## On use

  defmodule View do
    use Phoenix.Template, root: Path.join(__DIR__, "../fixtures/templates")
    import Phoenix.HTML

    def render("user.json", [name: name]) do
      Poison.encode! %{id: 123, name: name}
    end
  end

  test "render regular function definitions" do
    assert IO.iodata_to_binary(View.render("user.json", name: "eric")) ==
      "{\"name\":\"eric\",\"id\":123}"
  end

  test "render eex templates sanitizes against xss by default" do
    assert View.render("show.html") ==
           {:safe, "
Show!
\n"}

    assert View.render("show.html", message: "") ==
           {:safe, "
Show! <script>alert('xss');</script>
\n"}
  end

  test "render eex templates allows raw data to be injected" do
    html = View.render("safe.html", message: "")
    assert html == {:safe, "Raw \n"}
  end

  test "compiles templates from path" do
    assert View.render("show.html", message: "hello!") ==
           {:safe, "
Show! hello!
\n"}
  end

  test "compiler adds catch-all render/2 that raises UndefinedError" do
    assert_raise Phoenix.Template.UndefinedError, ~r/Could not render "not-exists.html".*/, fn ->
      View.render("not-exists.html")
    end
  end

  test "compiler ignores missing template path" do
    defmodule OtherViews do
      use Phoenix.Template, root: Path.join(__DIR__, "not-exists")
    end
  end

  test "generates phoenix_recompile? function" do
    refute View.phoenix_recompile?
  end
end

defmodule Phoenix.TemplateTest do
  use ExUnit.Case, async: true

  doctest Phoenix.Template
  alias Phoenix.Template

  @templates Path.expand("../fixtures/templates", __DIR__)

  test "template_path_to_name/2" do
    path = "/var/www/templates/admin/users/show.html.eex"
    root = "/var/www/templates"
    assert Template.template_path_to_name(path, root) ==
           "admin/users/show.html"

    path = "/var/www/templates/users/show.html.eex"
    root = "/var/www/templates"
    assert Template.template_path_to_name(path, root) ==
           "users/show.html"

    path = "/var/www/templates/home.html.eex"
    root = "/var/www/templates"
    assert Template.template_path_to_name(path, root) ==
           "home.html"

    path = "/var/www/templates/home.html.haml"
    root = "/var/www/templates"
    assert Template.template_path_to_name(path, root) ==
           "home.html"
  end

  test "find_all/1 finds all templates in the iven root" do
    templates = Template.find_all @templates
    assert Path.join(@templates, "show.html.eex") in templates

    templates = Template.find_all Path.dirname(@templates)
    assert templates == []
  end

  test "hash/1 returns the hash for the given root" do
    assert is_binary Template.hash(@templates)
  end

  test "format_encoder/1 returns the formatter for a given template" do
    assert Template.format_encoder("hello.html") == Phoenix.HTML.Engine
    assert Template.format_encoder("hello.unknown") == nil
  end

  ## On use

  defmodule View do
    use Phoenix.Template, root: Path.join(__DIR__, "../fixtures/templates")
    import Phoenix.HTML

    def render("user.json", [name: name]) do
      Poison.encode! %{id: 123, name: name}
    end
  end

  test "render regular function definitions" do
    assert IO.iodata_to_binary(View.render("user.json", name: "eric")) ==
      "{\"name\":\"eric\",\"id\":123}"
  end

  test "render eex templates sanitizes against xss by default" do
    assert View.render("show.html") ==
           {:safe, "
Show!
\n"}

    assert View.render("show.html", message: "") ==
           {:safe, "
Show! <script>alert('xss');</script>
\n"}
  end

  test "render eex templates allows raw data to be injected" do
    html = View.render("safe.html", message: "")
    assert html == {:safe, "Raw \n"}
  end

  test "compiles templates from path" do
    assert View.render("show.html", message: "hello!") ==
           {:safe, "
Show! hello!
\n"}
  end

  test "compiler adds catch-all render/2 that raises UndefinedError" do
    assert_raise Phoenix.Template.UndefinedError, ~r/Could not render "not-exists.html".*/, fn ->
      View.render("not-exists.html")
    end
  end

  test "compiler ignores missing template path" do
    defmodule OtherViews do
      use Phoenix.Template, root: Path.join(__DIR__, "not-exists")
    end
  end

  test "generates phoenix_recompile? function" do
    refute View.phoenix_recompile?
  end
end